Split string in c# - c#

I have a string whose format like "945-20-4:397-3:320" or "945-20-41-90-4:397-3:320" . I need to split it bases upon 1st ":" and last "-" from left of 1st ":".
Like for "945-20-4:397-3:320" I need 2 part like '945-20' & '4:397-3:320'.
For "945-20-41-90-4:37-3:320-1:232", 2 part will be like '945-20-41-90' and '4:37-3:320-1:232'.
How to spilt it?

Here you go 3:D
void Main()
{
Splitter.Print(Splitter.GetParts("945-20-4:397-3:320"));
Splitter.Print(Splitter.GetParts("945-20-41-90-4:397-3:320"));
}
unsafe static class Splitter
{
public static ValueTuple<string, string> GetParts(string whole)
{
var builder = new StringBuilder();
fixed (char* parts = whole)
{
char* lastDashPosition = null;
var terminus = parts + whole.Length;
for (var x = parts; x < terminus; ++x)
{
switch (*x)
{
case ':':
builder.Remove((int)(lastDashPosition - parts),
(int)(x - lastDashPosition));
return ValueTuple.Create(builder.ToString(),
whole.Substring((int)(lastDashPosition + 1 - parts)));
case '-':
lastDashPosition = x;
break;
}
builder.Append(*x);
}
throw new InvalidOperationException("String not in expected format.");
}
}
public static void Print(ValueTuple<string, string> v)
{
Debug.Print("Token 1: " + v.Item1);
Debug.Print("Token 2: " + v.Item2);
}
}

Related

Thousands separator after the decimal point [duplicate]

I wonder what would be the best way to format numbers so that the NumberGroupSeparator would work not only on the integer part to the left of the comma, but also on the fractional part, on the right of the comma.
Math.PI.ToString("###,###,##0.0##,###,###,###") // As documented ..
// ..this doesn't work
3.14159265358979 // result
3.141,592,653,589,79 // desired result
As documented on MSDN the NumberGroupSeparator works only to the left of the comma. I wonder why??
A little clunky, and it won't work for scientific numbers but here is a try:
class Program
{
static void Main(string[] args)
{
var π=Math.PI*10000;
Debug.WriteLine(Display(π));
// 31,415.926,535,897,931,899
}
static string Display(double x)
{
int s=Math.Sign(x);
x=Math.Abs(x);
StringBuilder text=new StringBuilder();
var y=Math.Truncate(x);
text.Append((s*y).ToString("#,#"));
x-=y;
if (x>0)
{
// 15 decimal places is max reasonable precision
y=Math.Truncate(x*Math.Pow(10, 15));
text.Append(".");
text.Append(y.ToString("#,#").TrimEnd('0'));
}
return text.ToString();
}
}
It might be best to work with the string generated by your .ToString():
class Program
{
static string InsertSeparators(string s)
{
string decSeparator = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;
int separatorPos = s.IndexOf(decSeparator);
if (separatorPos >= 0)
{
string decPart = s.Substring(separatorPos + decSeparator.Length);
// split the string into parts of 3 or less characters
List<String> parts = new List<String>();
for (int i = 0; i < decPart.Length; i += 3)
{
string part = "";
for (int j = 0; (j < 3) && (i + j < decPart.Length); j++)
{
part += decPart[i + j];
}
parts.Add(part);
}
string groupSeparator = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberGroupSeparator;
s = s.Substring(0, separatorPos) + decSeparator + String.Join(groupSeparator, parts);
}
return s;
}
static void Main(string[] args)
{
for (int n = 0; n < 15; n++)
{
string s = Math.PI.ToString("0." + new string('#', n));
Console.WriteLine(InsertSeparators(s));
}
Console.ReadLine();
}
}
Outputs:
3
3.1
3.14
3.142
3.141,6
3.141,59
3.141,593
3.141,592,7
3.141,592,65
3.141,592,654
3.141,592,653,6
3.141,592,653,59
3.141,592,653,59
3.141,592,653,589,8
3.141,592,653,589,79
OK, not my strong side, but I guess this may be my best bet:
string input = Math.PI.ToString();
string decSeparator = System.Threading.Thread.CurrentThread
.CurrentCulture.NumberFormat.NumberGroupSeparator;
Regex RX = new Regex(#"([0-9]{3})");
string result = RX.Replace(input , #"$1" + decSeparator);
Thanks for listening..

Decimal group seperator for the fractional part

I wonder what would be the best way to format numbers so that the NumberGroupSeparator would work not only on the integer part to the left of the comma, but also on the fractional part, on the right of the comma.
Math.PI.ToString("###,###,##0.0##,###,###,###") // As documented ..
// ..this doesn't work
3.14159265358979 // result
3.141,592,653,589,79 // desired result
As documented on MSDN the NumberGroupSeparator works only to the left of the comma. I wonder why??
A little clunky, and it won't work for scientific numbers but here is a try:
class Program
{
static void Main(string[] args)
{
var π=Math.PI*10000;
Debug.WriteLine(Display(π));
// 31,415.926,535,897,931,899
}
static string Display(double x)
{
int s=Math.Sign(x);
x=Math.Abs(x);
StringBuilder text=new StringBuilder();
var y=Math.Truncate(x);
text.Append((s*y).ToString("#,#"));
x-=y;
if (x>0)
{
// 15 decimal places is max reasonable precision
y=Math.Truncate(x*Math.Pow(10, 15));
text.Append(".");
text.Append(y.ToString("#,#").TrimEnd('0'));
}
return text.ToString();
}
}
It might be best to work with the string generated by your .ToString():
class Program
{
static string InsertSeparators(string s)
{
string decSeparator = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;
int separatorPos = s.IndexOf(decSeparator);
if (separatorPos >= 0)
{
string decPart = s.Substring(separatorPos + decSeparator.Length);
// split the string into parts of 3 or less characters
List<String> parts = new List<String>();
for (int i = 0; i < decPart.Length; i += 3)
{
string part = "";
for (int j = 0; (j < 3) && (i + j < decPart.Length); j++)
{
part += decPart[i + j];
}
parts.Add(part);
}
string groupSeparator = System.Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberGroupSeparator;
s = s.Substring(0, separatorPos) + decSeparator + String.Join(groupSeparator, parts);
}
return s;
}
static void Main(string[] args)
{
for (int n = 0; n < 15; n++)
{
string s = Math.PI.ToString("0." + new string('#', n));
Console.WriteLine(InsertSeparators(s));
}
Console.ReadLine();
}
}
Outputs:
3
3.1
3.14
3.142
3.141,6
3.141,59
3.141,593
3.141,592,7
3.141,592,65
3.141,592,654
3.141,592,653,6
3.141,592,653,59
3.141,592,653,59
3.141,592,653,589,8
3.141,592,653,589,79
OK, not my strong side, but I guess this may be my best bet:
string input = Math.PI.ToString();
string decSeparator = System.Threading.Thread.CurrentThread
.CurrentCulture.NumberFormat.NumberGroupSeparator;
Regex RX = new Regex(#"([0-9]{3})");
string result = RX.Replace(input , #"$1" + decSeparator);
Thanks for listening..

Best way to extract two numbers and following letter from string

Say we have a string, called source. It contains "New York City - 12A - 1234B"
Here are the rules:
a. We know that the closest two numbers to the beginning of the string should kept, along with the following character and placed into a separate string, called results;
b. We are not certain if this following character will be a number or a letter
c. The formatting of the string itself varies - it could be "NY 12A 1234B"
d. We could care less about anything else!
Now I in my infinite wisdom have crafted this monstrosity. It works but please tell me there is a better way to do this or at best a cleaner, more performance conscious way of doing it.
class Program
{
public static int i = 0;
public static int q = 0;
public static int x = 0;
public static string source = "New York City - 12A - 1234B";
public static string results = "";
public static char[] from_source_char;
public static List<string> from_source_list = new List<string>();
static void Main(string[] args)
{
from_source_char = source.ToCharArray();
foreach (char unit in from_source_char)
{
from_source_list.Add(unit.ToString());
}
Console.WriteLine("Doing while " + i.ToString() + " < " + (from_source_list.Count() - 1).ToString());
while (i < from_source_list.Count() - 1)
{
Console.WriteLine("i is at " + i.ToString());
Console.WriteLine("Examining " + from_source_list[i].ToString());
try
{
q = Convert.ToInt32(from_source_list[i]);
results += from_source_list[i].ToString();
Console.WriteLine("Found part 1!");
x++;
}
catch
{
Console.WriteLine("Disregarding " + from_source_list[i].ToString());
// do nothing
}
if (x == 2)
{
Console.WriteLine("Found final part! " + from_source_char[i+1].ToString());
results += from_source_char[i+1].ToString();
break;
}
i++;
}
Console.WriteLine("Result is " + results.ToString());
Thread.Sleep(999999);
}
}
You could use a Regex with this pattern: #"^.*?(?<numbers>\d{2}\w).*$".
Example:
var f = #"^.*?(?<numbers>\d{2}\w).*$";
var match = Regex.Match("NY 12A 1234B", f);
var result = match.Groups["numbers"].Value;
Another version without regex:
char a = source.First(pos => char.IsDigit(pos));
int b = source.IndexOf(a);
string result = source.Substring(b, 3);
Console.WriteLine(result);

How do i get the numbers from the GetKey back to the List<float>? (Reverse of what i did)

This is the code for the SetKey i loop over the Lists take out the numbers convert to string and put it in to the SetKey now i need to reverse the action using GetKey and put back the numbers to the Lists so eahc List Point_X and Point_Y will have the numbers as before.
string[] xFrames = new string[wocl.Count];
string[] yFrames = new string[wocl.Count];
string X="";
string Y="";
for (int i = 0; i < wocl.Count; i++)
{
X = string.Format("Frame_X_{0} ", i + 1);
Y = string.Format("Frame_Y_{0} ", i + 1);
for (int j = 0; j < wocl[i].Point_X.Count; j++)
{
xFrames[i] += string.Format("{0},", wocl[i].Point_X[j]);
yFrames[i] += string.Format("{0},", wocl[i].Point_Y[j]);
}
string tt = xFrames[i].Trim(",".ToCharArray());
string yy = yFrames[i].Trim(",".ToCharArray());
setting_file.SetKey(X, tt);
setting_file.SetKey(Y, yy);
}
Now tt is a string of number for example 122,33,44,55,121
Now i need to parse the numbers back. Now i need to take the string and parse the numbers and put them back to a float List:
List a = setting_file.GetKey(X);
But X is a key that present a string of numbers not a List of numbers.
This is the code in the OptionsFile of the functions GetKey and SetKey:
/*----------------------------------------------------------
* Function : GetKey
* Description : gets the value of the key.
* Parameters : key
* Return : value of the key if key exist, null if not exist
* --------------------------------------------------------*/
public string GetKey(string key)
{
// string value_of_each_key;
string key_of_each_line;
string line;
int index;
string key_value;
key_value = null;
sr = new StreamReader(Options_File);
while (null != (line = sr.ReadLine()))
{
index = line.IndexOf("=");
// value_of_each_key = line.Substring(index+1);
if (index >= 1)
{
key_of_each_line = line.Substring(0, index);
if (key_of_each_line == key)
{
key_value = line.Substring(key.Length + 1);
}
}
else
{
}
}
sr.Close();
return key_value;
}
/*----------------------------------------------------------
* Function : SetKey
* Description : sets a value to the specified key
* Parameters : key and a value
* Return : none
* --------------------------------------------------------*/
public void SetKey(string key , string value)
{
bool key_was_found_inside_the_loop;
string value_of_each_key;
string key_of_each_line ;
string line;
int index;
key_was_found_inside_the_loop = false;
temp_settings_file = "\\temp_settings_file.txt";
temp_settings_dir = path_exe + #"\temp_settings";
if (!Directory.Exists(temp_settings_dir))
{
Directory.CreateDirectory(temp_settings_dir);
}
sw = new StreamWriter(temp_settings_dir+temp_settings_file);
sr = new StreamReader(Options_File);
while (null != (line = sr.ReadLine()))
{
index = line.IndexOf("=");
key_of_each_line = line.Substring(0, index);
value_of_each_key = line.Substring( index + 1);
// key_value = line.Substring(0,value.Length);
if (key_of_each_line == key)
{
sw.WriteLine(key + " = " + value);
key_was_found_inside_the_loop = true;
}
else
{
sw.WriteLine(key_of_each_line+"="+value_of_each_key);
}
}
if (!key_was_found_inside_the_loop)
{
sw.WriteLine(key + "=" + value);
}
sr.Close();
sw.Close();
File.Delete(Options_File);
File.Move(temp_settings_dir + temp_settings_file, Options_File);
return;
}
What i need is that in the List a it will contain the numbers from the string X
X is like a key the result in SetKey function is a Key = Value
For example : Hello = 122,33,44,55,66 Hello is like the variable X its the key and on the right hand the numbers are the key values.
So now i need to get the key X values and put them into the List
Cant figure out how to do it.
If before i had a List and i loop over it and took out the numbers from the List and created a string of the numbers and put them in the SetKey now i need to use the GetKey and take the numbers and put them back to the List
Edit:
public void Load(string path,string fileName)
{
string X = "";
string t = path + "\\" + fileName;
OptionsFile setting_file = new OptionsFile(t);
for (int i = 0; i <= wocl.Count ; i++)
{
X = string.Format("Frame_X_{0} ", i + 1);
}
string test = setting_file.GetKey(X);
}
Thep roblem is that if im running in the loop on the List wocl so when im running the program this List is count 0 or 1. But in the GetKey in the text file i might have 4 frames or 1 frame i mean how do i know on how much to count for in the loop ?
I tried with the wocl List for the test but now in the string test im getting the numbers of the first Frame_X_1 but thats it.
While in hte file it self it looks like:
Frame_X_1 =332,325,336,334,332,325,333,328,332
Frame_Y_1 =218,217,202,212,211,210,204,202,204
Frame_X_2 =270,325,336,347,321,325,333,328,332
Frame_Y_2 =257,217,202,282,156,210,204,202,204
Frame_X_3 =270,325,336,347,321,336,270,371,332
Frame_Y_3 =257,217,202,282,156,250,199,135,204
I mean when im running the program all the Lists are empty count to 0 and yet i need to retrive each key Frame_X_1 then Frame_Y_1 and so on...And i dont know how many keys there are.
Add this to a static helper class
public static List<T> ToListOf<T>(this IEnumerable enumerable)
{
var list = new List<T>();
foreach (var item in enumerable)
{
list.Add(item.ConvertTo<T>());
}
return list;
}
then: var myFloats = tt.Split(',').ToListOf<float>();
elegant, no? :)
EDIT
I forgot one more extension method:
public static T ConvertTo<T>(this object source)
{
return (T)Convert.ChangeType(source, typeof(T));
}
Suppose you have a string like "123,33.44.55.66" and you know that this string is comma delimited. to retrieve the numbers:
string str = "123,33,44,55,66";
string[] strArray = str.Split(',');
you can then convert the strArray to any type compatible.

Concatenating an array of strings to "string1, string2 or string3"

Consider the following code:
string[] s = new[] { "Rob", "Jane", "Freddy" };
string joined = string.Join(", ", s);
// joined equals "Rob, Jane, Freddy"
For UI reasons I might well want to display the string "Rob, Jane or Freddy".
Any suggestions about the most concise way to do this?
Edit
I am looking for something that is concise to type. Since I am only concatenating small numbers (<10) of strings I am not worried about run-time performance here.
Concise meaning to type? or to run? The fastest to run will be hand-cranked with StringBuilder. But to type, probably (edit handle 0/1 etc):
string joined;
switch (s.Length) {
case 0: joined = ""; break;
case 1: joined = s[0]; break;
default:
joined = string.Join(", ", s, 0, s.Length - 1)
+ " or " + s[s.Length - 1];
break;
}
The StringBuilder approach might look something like:
static string JoinOr(string[] values) {
switch (values.Length) {
case 0: return "";
case 1: return values[0];
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < values.Length - 2; i++) {
sb.Append(values[i]).Append(", ");
}
return sb.Append(values[values.Length-2]).Append(" or ")
.Append(values[values.Length-1]).ToString();
}
Concatenate all but the last one. Do the last one manually.
Create an extension method on string[] that implement the same logic as string.Join but the last item will be appended with "or".
string[] s = new[] { "Rob", "Jane", "Freddy" };
Console.WriteLine(s.BetterJoin(", ", " or "));
// ---8<----
namespace ExtensionMethods
{
public static class MyExtensions
{
public static string BetterJoin(this string[] items, string separator, string lastSeparator)
{
StringBuilder sb = new StringBuilder();
int length = items.Length - 2;
int i = 0;
while (i < length)
{
sb.AppendFormat("{0}{1}", items[i++], separator);
}
sb.AppendFormat("{0}{1}", items[i++], lastSeparator);
sb.AppendFormat("{0}", items[i]);
return sb.ToString();
}
}
}
What about:
if (s.Length > 1)
{
uiText = string.Format("{0} and {1}", string.Join(", ", s, 0, s.Length - 1), s[s.Length - 1]);
}
else
{
uiText = s.Length > 0 ? s[0] : "";
}
Generic solution for any type T.
static class IEnumerableExtensions
{
public static string Join<T>(this IEnumerable<T> items,
string seperator, string lastSeperator)
{
var sep = "";
return items.Aggregate("", (current, item) =>
{
var result = String.Concat(current,
// not first OR not last
current == "" || !items.Last().Equals(item) ? sep : lastSeperator,
item.ToString());
sep = seperator;
return result;
});
}
}
Usage:
var three = new string[] { "Rob", "Jane", "Freddy" };
var two = new string[] { "Rob", "Jane" };
var one = new string[] { "Rob" };
var threeResult = three.Join(", ", " or "); // = "Rob, Jane or Freddy"
var twoResult = two.Join(", ", " or "); // = "Rob or Jane"
var oneResult = one.Join(", ", " or "); // = "Rob"
The most memory efficient and scalable would be using a StringBuilder and precalculating the length of the final string to elliminate buffer reallocations. (This is similar to how the String.Concat method works.)
public static string Join(string[] items, string separator, string lastSeparator) {
int len = separator.Length * (items.Length - 2) + lastSeparator.Length;
foreach (string s in items) len += s.Length;
StringBuilder builder = new StringBuilder(len);
for (int i = 0; i < items.Length; i++) {
builder.Append(items[i]);
switch (items.Length - i) {
case 1: break;
case 2: builder.Append(lastSeparator); break;
default: builder.Append(separator); break;
}
}
return builder.ToString();
}
Usage:
string joined = Join(s, ", ", " or ");
An interresting solution would be using a recursive algorithm. It works well for a reasonably small number of strings, but it doesn't scale very well.
public static string Join(string[] items, int index , string separator, string lastSeparator) {
return items[index++] + (index == items.Length-1 ? lastSeparator + items[index] : separator + Join(items, index, separator, lastSeparator));
}
Usage:
string joined = Join(s, 0, ", ", " or ");
string[] name_storage = new[] { "emre" , "balc" };
name_storage[name_storage.Count() - 1] += "ı";
string name = name_storage[0];
string sur_name = name_storage[1];
divElement.InnerHtml += name + " - " + sur_name;
//result = emre - balcı

Categories