What's the easiest way to format a numeric string? - c#

I have the following string: "12345678901", and I want it to be formatted as "123.456.789-01",
I'm currently doing it like this:
string s = "12345678901";
string formatted = Int64.Parse(s).ToString("000.000.000-00"); // = "123.456.789-01"
Is there a better way of doing this, can I do this directly, without having to convert the string to int and back to string again?

Yes, you can reach your result without conversion to an integer and reformatting the integer to a string and it is even faster.
s = "12345678901";
StringBuilder sb = new StringBuilder(s);
int pos = s.Length - 2;
if (pos > 0) sb.Insert(pos, "-");
pos -= 3;
while (pos > 0)
{
sb.Insert(pos, ".");
pos -= 3;
}
string formatted = sb.ToString();
This is more or less what madrereflection has told you in comments with the only difference that the example here uses StringBuilder to avoid the continuous rebuild of the string. From simple benchmark it is three times faster than the current approach but of course more code is required.

Related

How get odd chars from String in C#

I am new to C#. My problem is to take odd chars from a string and get a new string from those odds.
string name = "Filip"; // expected output ="Flp"
I don't want to take, for example,
string result = name.Substring(0, 1) + name.Substring(2, 1) + ... etc.
I need a function for this operation.
Try Linq (you actually want even characters since string is zero-based):
string name = "Filip";
string result = string.Concat(name.Where((c, i) => i % 2 == 0));
In case of good old loop implementation, I suggest building the string with a help of StringBuilder:
StringBuilder sb = new StringBuilder(name.Length / 2 + 1);
for (int i = 0; i < name.Length; i += 2)
sb.Append(name[i]);
string result = sb.ToString();

How can I slice a string in c#?

string word = "hello";
So what I want to do is slice the string so that I can print, for example, elloh to the console window. In python it's so simple but I'm not sure if there's a specific method for slicing in c#.
A string can be indexed to get characters:
string word = "hello";
char h = word[0];
or strings have methods for "slicing":
int start = 0;
int length = 1;
string h = word.Substring(start, length);
Why not read the docs and find out for yourself?
There's no exact translation from the concept of a slicing, but a Substring is generally what you want.
It is unclear to me what your exact criteria is to slice it up, but this would do what you want:
void Main()
{
var input = "hello";
var output = input.Substring(1, input.Length - 1) + input.Substring(0, 1);
Console.WriteLine (output);
}
To "slice" a string, you use the Substring method:
string word = "hello";
string ordw = word.Substring(1) + word.Substring(0, 1);
However, a different answer would be to check out NSlice, a library built to handle python-like slicing of arrays.
Will it make it easier to do what you asked? No. Will it make it easier to "slice" different kinds of collections? Possibly.
you should use the substring function of string:
word.Substring(1);
http://msdn.microsoft.com/en-us/library/system.string.substring(v=vs.110).aspx
Maybe you want an extension method like this:
public static string Rotate(this string s, int numberOfChars)
{
if (string.IsNullOrEmpty(s))
return s;
numberOfChars %= s.Length;
if (numberOfChars == 0)
return s;
if (numberOfChars < 0)
numberOfChars += s.Length;
return s.Substring(numberOfChars) + s.Remove(numberOfChars);
}

code translation: repeating a string until some maximum

I was wondering if you could tell me what the most efficient way to repeat a string would be. I need to create a string 33554432 bytes long, repeating the string "hello, world" until it fills that buffer. What is the best way to do it, C is easy in this case:
for (i = 0; i < BIGSTRINGLEN - step; i += step)
memcpy(bigstring+i, *s, step);
Thanks.
An efficient way would be to use a StringBuilder:
string text = "hello, world";
StringBuilder builder = new StringBuilder(BIGSTRINGLEN);
while (builder.Length + text.Length <= BIGSTRINGLEN) {
builder.Append(text);
}
string result = builder.ToString();
First, do you want the string to be 33554432 bytes long, or characters long? .NET and C# use 16-bit characters, so they are not equivalent.
If you want 33554432 characters, naive solution would be string concatenation. See Frédéric Hamidi's answer.
If you want bytes, you will need to do something a bit more interesting:
int targetLength = 33554432;
string filler = "hello, world";
byte[] target = new byte[targetLength];
// Convert filler to bytes. Can use other encodings here.
// I am using ASCII to match C++ output.
byte[] fillerBytes = Encoding.ASCII.GetBytes(filler);
//byte[] fillerBytes = Encoding.Unicode.GetBytes(filler);
//byte[] fillerBytes = Encoding.UTF8.GetBytes(filler);
int position = 0;
while((position + fillerBytes.Length) < target.Length)
{
fillerBytes.CopyTo(target, position);
position += fillerBytes.Length;
}
// At this point, need to possibly do a partial copy.
if (position < target.Length)
{
int bytesNecessary = target.Length - position;
Array.Copy(fillerBytes, 0, target, position, bytesNecessary);
}
I don't know if it's the most efficient way, but if you're using .NET 3.5 or later, this could work:
String.Join("", System.Linq.Enumerable.Repeat("hello, world", 2796203).ToArray()).Substring(0, 33554432);
If the length you want is dynamic, then you can replace some of the hard-coded numbers with simple math.
What about this? Set the StringBuilder to the max expected size and then add the desired string as long as adding another one will not exceed the desired max size.
StringBuilder sb = new StringBuilder(33554432);
int max = sb.MaxCapacity;
String hello = "hello, world";
while (sb.Length + hello.Length <= max)
{
sb.Append(hello);
}
string longString = sb.ToString();
This avoids a loop that repeatedly adds the string. Instead, I "double" the string until it gets close to the right length and then I put the "doubled" pieces together appropriately.
static string Repeat(string s, int length) {
if (length < s.Length) {
return s.Substring(0, length);
}
var list = new List<string>();
StringBuilder t = new StringBuilder(s);
do {
string temp = t.ToString();
list.Add(temp);
t.Append(temp);
} while(t.Length < length);
int index = list.Count - 1;
StringBuilder sb = new StringBuilder(length);
while (sb.Length < length) {
while (list[index].Length > length) {
index--;
}
if (list[index].Length <= length - sb.Length) {
sb.Append(list[index]);
}
else {
sb.Append(list[index].Substring(0, length - sb.Length));
}
}
return sb.ToString();
}
So, for example, on input ("Hello, world!", 64) we build the strings
13: Hello, World!
26: Hello, World!Hello, World!
52: Hello, World!Hello, World!Hello, World!Hello, World!
Then we would build the result by concatenating the string of length 52 to the substring of length 12 of the string of length 13.
I am, of course, assuming that by bytes you meant length. Otherwise, you can easily modify the above using encodings to get what you want in terms of bytes.

Format string with dashes

I have a compressed string value I'm extracting from an import file. I need to format this into a parcel number, which is formatted as follows: ##-##-##-###-###. So therefore, the string "410151000640" should become "41-01-51-000-640". I can do this with the following code:
String.Format("{0:##-##-##-###-###}", Convert.ToInt64("410151000640"));
However, The string may not be all numbers; it could have a letter or two in there, and thus the conversion to the int will fail. Is there a way to do this on a string so every character, regardless of if it is a number or letter, will fit into the format correctly?
Regex.Replace("410151000640", #"^(.{2})(.{2})(.{2})(.{3})(.{3})$", "$1-$2-$3-$4-$5");
Or the slightly shorter version
Regex.Replace("410151000640", #"^(..)(..)(..)(...)(...)$", "$1-$2-$3-$4-$5");
I would approach this by having your own formatting method, as long as you know that the "Parcel Number" always conforms to a specific rule.
public static string FormatParcelNumber(string input)
{
if(input.length != 12)
throw new FormatException("Invalid parcel number. Must be 12 characters");
return String.Format("{0}-{1}-{2}-{3}-{4}",
input.Substring(0,2),
input.Substring(2,2),
input.Substring(4,2),
input.Substring(6,3),
input.Substring(9,3));
}
This should work in your case:
string value = "410151000640";
for( int i = 2; i < value.Length; i+=3){
value = value.Insert( i, "-");
}
Now value contains the string with dashes inserted.
EDIT
I just now saw that you didn't have dashes between every second number all the way, to this will require a small tweak (and makes it a bit more clumsy also I'm afraid)
string value = "410151000640";
for( int i = 2; i < value.Length-1; i+=3){
if( value.Count( c => c == '-') >= 3) i++;
value = value.Insert( i, "-");
}
If its part of UI you can use MaskedTextProvider in System.ComponentModel
MaskedTextProvider prov = new MaskedTextProvider("aa-aa-aa-aaa-aaa");
prov.Set("41x151000a40");
string result = prov.ToDisplayString();
Here is a simple extension method with some utility:
public static string WithMask(this string s, string mask)
{
var slen = Math.Min(s.Length, mask.Length);
var charArray = new char[mask.Length];
var sPos = s.Length - 1;
for (var i = mask.Length - 1; i >= 0 && sPos >= 0;)
if (mask[i] == '#') charArray[i--] = s[sPos--];
else
charArray[i] = mask[i--];
return new string(charArray);
}
Use it as follows:
var s = "276000017812008";
var mask = "###-##-##-##-###-###";
var dashedS = s.WithMask(mask);
You can use it with any string and any character other than # in the mask will be inserted. The mask will work from right to left. You can tweak it to go the other way if you want.
Have fun.
If i understodd you correctly youre looking for a function that removes all letters from a string, aren't you?
I have created this on the fly, maybe you can convert it into c# if it's what you're looking for:
Dim str As String = "410151000vb640"
str = String.Format("{0:##-##-##-###-###}", Convert.ToInt64(MakeNumber(str)))
Public Function MakeNumber(ByVal stringInt As String) As String
Dim sb As New System.Text.StringBuilder
For i As Int32 = 0 To stringInt.Length - 1
If Char.IsDigit(stringInt(i)) Then
sb.Append(stringInt(i))
End If
Next
Return sb.ToString
End Function

c# getting a string within another string

i have a string like this:
some_string = "A simple demo of SMS text messaging.\r\n+CMGW: 3216\r\n\r\nOK\r\n\"
im coming from vb.net and i need to know in c#, if i know the position of CMGW, how do i get "3216" out of there?
i know that my start should be the position of CMGW + 6, but how do i make it stop as soon as it finds "\r" ??
again, my end result should be 3216
thank you!
Find the index of \r from the start of where you're interested in, and use the Substring overload which takes a length:
// Production code: add validation here.
// (Check for each index being -1, meaning "not found")
int cmgwIndex = text.IndexOf("CMGW: ");
// Just a helper variable; makes the code below slightly prettier
int startIndex = cmgwIndex + 6;
int crIndex = text.IndexOf("\r", startIndex);
string middlePart = text.Substring(startIndex, crIndex - startIndex);
If you know the position of 3216 then you can just do the following
string inner = some_string.SubString(positionOfCmgw+6,4);
This code will take the substring of some_string starting at the given position and only taking 4 characters.
If you want to be more general you could do the following
int start = positionOfCmgw+6;
int endIndex = some_string.IndexOf('\r', start);
int length = endIndex - start;
string inner = some_string.SubString(start, length);
One option would be to start from your known index and read characters until you hit a non-numeric value. Not the most robust solution, but it will work if you know your input's always going to look like this (i.e., no decimal points or other non-numeric characters within the numeric part of the string).
Something like this:
public static int GetNumberAtIndex(this string text, int index)
{
if (index < 0 || index >= text.Length)
throw new ArgumentOutOfRangeException("index");
var sb = new StringBuilder();
for (int i = index; i < text.Length; ++i)
{
char c = text[i];
if (!char.IsDigit(c))
break;
sb.Append(c);
}
if (sb.Length > 0)
return int.Parse(sb.ToString());
else
throw new ArgumentException("Unable to read number at the specified index.");
}
Usage in your case would look like:
string some_string = #"A simple demo of SMS text messaging.\r\n+CMGW: 3216\r\n...";
int index = some_string.IndexOf("CMGW") + 6;
int value = some_string.GetNumberAtIndex(index);
Console.WriteLine(value);
Output:
3216
If you're looking to extract the number portion of 'CMGW: 3216' then a more reliable method would be to use regular expressions. That way you can look for the entire pattern, and not just the header.
var some_string = "A simple demo of SMS text messaging.\r\n+CMGW: 3216\r\n\r\nOK\r\n";
var match = Regex.Match(some_string, #"CMGW\: (?<number>[0-9]+)", RegexOptions.Multiline);
var number = match.Groups["number"].Value;
More general, if you don't know the start position of CMGW but the structure remains as before.
String s;
char[] separators = {'\r'};
var parts = s.Split(separators);
parts.Where(part => part.Contains("CMGW")).Single().Reverse().TakeWhile(c => c != ' ').Reverse();

Categories

Resources