I am trying to remove part of string value from var1 and then pasting it into another var2 and then into var2. While doing so I update the values of the original variables. So if string length in var1 exceeds max length of 10 it then carries out this manipulation.
The code shown below works fine however I am not sure if this is the best approach of removing part of string and assigning it to a var, updating the value in original variable etc
if (var1.Length > 10)
{
var newVar2 = var1.Remove(0, 10); // Grab the string from var1 and assign
var1 = var1.Remove(10); // Update value and remove the part of string
var2 = newVar2; // Save the newly removed string into var2
if (var2.Length > 10)
{
var newVar3 = var2.Remove(0, 10);
var2 = var2.Remove(10);
var3 = newVar3;
}
}
Is there a better approach?
There are several approaches for string manipulation, but for your case just slimming down your code a bit to remove unneccesary assignments and instantiation should be fine:
if (var1.Length > 10) {
var2 = var1.Remove(0, 10);
var1 = var1.Remove(10);
if (var2.Length > 10) {
var3 = var2.Remove(0, 10);
var2 = var2.Remove(10);
}
}
Another option is to store the string in a List<string> via a loop; this way you won't need a new var for every occasion that the length exceeds 10:
private List<string> SlimStrings(string var1) {
List<string> vars = new List<string>();
string val = string.Empty;
for (int i = 0; i < var1.Length; i++) {
if (i % 10 == 0) {
vars.Add(val);
val = string.Empty;
}
val += var1[i];
}
return vars;
}
In this situation the final string in vars should be less than or equal to 10 in length. Everything prior should be equal to 10 in length. You then access each var via it's index (remembering that C# is a zero based language):
List<string> vars = SlimStrings("askljdngakjdsfngiewurnkajsdnicoebrlpvknas");
var var1 = vars[0];
var var2 = vars[1];
var var3 = vars[2];
Now granted, you'll either have to know the Count of vars in the list prior, or come up with a system for accessing such as a loop like the one that created it (or a foreach loop for simplicity) following the same principal:
private void UseVars(List<string> vars) {
foreach (string s in vars)
DoSomethingWith(s);
// OR
for (int i = 0; i < vars.Count; i++)
DoSomethingWith(vars[i]);
}
Spaces count when working with strings. Unless you truly want spaces in your new values, you should use trim() to remove leading and trailing spaces.
Hard to know what your requirements are given your question. Strings are immutable so you're creating new strings when you do string the string manipulation that you've shown. In general you'd like to create as few as possible. If you're requirements are to create multiple strings from a single string you have no choice, if you're building a single string use StringBuilder. If you're simply truncating the string then just do it in one shot:
var input = "abcdefghijklmnopqrstuvwxyz";
Console.WriteLine($"{input.Length}: {input}");
var truncated = input.Remove(0, input.Length - 10);
Console.WriteLine($"{truncated.Length}: {truncated}");
Related
The string I want to split is an array of strings.
the array contains strings like:
G1,Active
G2,Inactive
G3,Inactive
.
.
G24,Active
Now I want to store the G's in an array, and Active or Inactive in a different array. So far I have tried this which has successfully store all the G's part but I have lost the other part. I used Split fucntion but did not work so I have tried this.
int i = 0;
for(i = 0; i <= grids.Length; i++)
{
string temp = grids[i];
temp = temp.Replace(",", " ");
if (temp.Contains(' '))
{
int index = temp.IndexOf(' ');
grids[i] = temp.Substring(0, index);
}
//System.Console.WriteLine(temp);
}
Please help me how to achieve this goal. I am new to C#.
If I understand the problem correctly - we have an array of strings Eg:
arrayOfStrings[24] =
{
"G1,Active",
"G2,Inactive",
"G3,Active",
...
"G24,Active"
}
Now we want to split each item and store the g part in one array and the status into another.
Working with arrays the solution is to - traverse the arrayOfStrings.
Per each item in the arrayOfStrings we split it by ',' separator.
The Split operation will return another array of two elements the g part and the status - which will be stored respectively into distinct arrays (gArray and statusArray) for later retrieval. Those arrays will have a 1-to-1 relation.
Here is my implementation:
static string[] LoadArray()
{
return new string[]
{
"G1,Active",
"G2,Inactive",
"G3,Active",
"G4,Active",
"G5,Active",
"G6,Inactive",
"G7,Active",
"G8,Active",
"G9,Active",
"G10,Active",
"G11,Inactive",
"G12,Active",
"G13,Active",
"G14,Inactive",
"G15,Active",
"G16,Inactive",
"G17,Active",
"G18,Active",
"G19,Inactive",
"G20,Active",
"G21,Inactive",
"G22,Active",
"G23,Inactive",
"G24,Active"
};
}
static void Main(string[] args)
{
string[] myarrayOfStrings = LoadArray();
string[] gArray = new string[24];
string[] statusArray = new string[24];
int index = 0;
foreach (var item in myarrayOfStrings)
{
var arraySplit = item.Split(',');
gArray[index] = arraySplit[0];
statusArray[index] = arraySplit[1];
index++;
}
for (int i = 0; i < gArray.Length; i++)
{
Console.WriteLine("{0} has status : {1}", gArray[i] , statusArray[i]);
}
Console.ReadLine();
}
seems like you have a list of Gxx,Active my recomendation is first of all you split the string based on the space, which will give you the array previoulsy mentioned doing the next:
string text = "G1,Active G2,Inactive G3,Inactive G24,Active";
string[] splitedGItems = text.Split(" ");
So, now you have an array, and I strongly recommend you to use an object/Tuple/Dictionary depends of what suits you more in the entire scenario. for now i will use Dictionary as it seems to be key-value
Dictionary<string, string> GxListActiveInactive = new Dictionary<string, string>();
foreach(var singleGItems in splitedGItems)
{
string[] definition = singleGItems.Split(",");
GxListActiveInactive.Add(definition[0], definition[1]);
}
What im achiving in this code is create a collection which is key-value, now you have to search the G24 manually doing the next
string G24Value = GxListActiveInactive.FirstOrDefault(a => a.Key == "G24").Value;
just do it :
var splitedArray = YourStringArray.ToDictionary(x=>x.Split(',')[0],x=>x.Split(',')[1]);
var gArray = splitedArray.Keys;
var activeInactiveArray = splitedArray.Values;
I hope it will be useful
You can divide the string using Split; the first part should be the G's, while the second part will be "Active" or "Inactive".
int i;
string[] temp, activity = new string[grids.Length];
for(i = 0; i <= grids.Length; i++)
{
temp = grids[i].Split(',');
grids[i] = temp[0];
activity[i] = temp[1];
}
I have string delimited by the pipe character. It is a repeatable sequence:
<machinenr>|<controldone>|<nrofitems|<items>
However where you see the items tag, you will have itemnumbers delimited also by the pipe character inbetween. Well, its' not a smart format, but I have to solve it, and I want to do with with regex in C#. So assuming the above format lets have a real example:
446408|0|2|111|6847|446408||0||
Note theoretically there doesn't need to be a value between the pipes, nor are the contents limited by a length. An item Id can be 111 or 877333, but even a mixed alphanumeric id XB111. So here we have a two machines with no items:
446408|0|0||447400||0||
Here we have a few machines with no or some items. Note, the pipe character is also used to delimit the items, so you have pipes within pipes:
446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0||
This machine has three items:
446408|0|3|99884|111|73732|
The item ids:
99884|111|73732
What should the regex look like? I've tried with the below named groups (easier to read), but it just doesn't work:
^(?P<machinenr>.*?)\|
(?P<controldone>.*?)\|
(?P<nrofitems>.*?)\|
(?P<items>.*?)\|
Here is a clarification for #Atterson #sln and #. Note, the amount of items can be 0-n there is no limit to the amount. Lets take this example, a long string with machines, and their items: 446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0|| What I expect the regex to do is to break up this string into three matches/parts and their values, the first match being: 446408|0|1|111| the second match: 446408|0|3|99884|111|73732| and the third match: 446408|0|0|| Ok, so to take an example of the values each part is supposed to be split into, lets use the second match/part. It is a machine with nr 446408, it has not been controlled 0, it has 3 items, the item ids: 99884|111|73732. After these items, a new sequence of:
<machinenr>|<controldone>|<nrofitems|<items>
can follow. #Sanxofon please check your regex here: [link] https://regex101.com/r/kC3gH0/87 and you'll see unfortunately it does not match.
This isn't solvable with a regex, there's no way to tell the regular expression something like: "Match .*?\| the same number of times as a certain capturing group...which happens to contain a number." This is the straightforward solution to this problem using plain old C# though.
string items = "446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0|";
var fields = items.Split('|');
for (int i = 0; i < fields.Length;) {
Console.WriteLine("machinenr:" + fields[i++]);
Console.WriteLine("controldone:" + fields[i++]);
int numSubItems = Int32.Parse(fields[i++]);
Console.WriteLine("num subitems:" + numSubItems);
if (numSubItems == 0) {
i++;
continue;
}
for (int subItemIndex = 0; subItemIndex < numSubItems; subItemIndex++) {
Console.WriteLine("\tItem:" + (subItemIndex + 1) + ": " + fields[i++]);
}
}
FYI, I trimmed the trailing "|" that your original string had, so
string items = "446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0|";
instead of
string items = "446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0||";
Named capturing groups are (?<nam>...) not (?P<name>...) in C#. Also, you expressed the desire to have repeating matches (so I have wrapped your regex in a repeating (?<grp>..).
You need to figure out how to differentiate an item from a machine. For instance, if you could say all machine numbers were 6 digits, and items were 0-5 digits you could do something like this... You would still have to split out the items collection.
^(?<grp>(?<machinenr>[^\|]{6})\|
(?<controldone>[^\|]*)\|
(?<nrofitems>[^\|]*)\|
(?<items>(?:[^\|]{0,5}\|){1,}))*$
Sample C# implementation:
class Program
{
static void Main(string[] args)
{
string strRegex =
#"^(?<grp>(?<machinenr>[^\|]{6})\|
(?<controldone>[^\|]*)\|
(?<nrofitems>[^\|]*)\|
(?<items>(?:[^\|]{0,5}\|){1,}))*$";
Regex myRegex = new Regex(strRegex, RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
string strTargetString = #"446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0||";
MatchCollection matches = myRegex.Matches(strTargetString);
foreach (Match m in matches)
{
for (int idx = 0; idx < m.Groups["grp"].Captures.Count; idx++)
{
Console.WriteLine("Group:");
Console.WriteLine($"\tmachinenr={m.Group["machinenr"].Captures[idx]}");
Console.WriteLine($"\tcontroldone={m.Groups["controldone"].Captures[idx]}");
Console.WriteLine($"\tnrofitems={m.Groups["nrofitems"].Captures[idx]}");
Console.WriteLine($"\titems={m.Groups["items"].Captures[idx]}");
}
}
}
}
Using C# IEnumerable<T> Algorithm
It would seem easier just to split the string and parse the subsequent array. But, if you are concerned about dealing with large strings or don't wish to use String.Split(), you can use an IEnumerable<T> method. Here is one approach...
class Program
{
public class Entry
{
public string MachineNr { get; set; }
public string ControlDone { get; set; }
public int Count { get; set; }
public List<string> Items { get; set; }
private static IEnumerable<string> fields(string list)
{
int idx = 0;
do
{
int ndx = list.IndexOf('|', idx);
if (ndx == 1)
yield return list.Substring(idx);
else
yield return list.Substring(idx, ndx - idx);
idx = ++ndx;
}
while (idx > 0 && idx < list.Length-1) ;
}
public static IEnumerable<Entry> parseList(string list)
{
int idx =0;
var fields = Entry.fields(list).GetEnumerator();
while (fields.MoveNext())
{
var e = new Entry();
e.MachineNr = fields.Current;
if (fields.MoveNext())
{
e.ControlDone = fields.Current;
if (fields.MoveNext())
{
int val = 0;
e.Count = int.TryParse(fields.Current, out val) ? val : 0;
e.Items = new List<string>();
for (int x=e.Count;x>0;x--)
{
if (fields.MoveNext())
e.Items.Add(fields.Current);
}
}
}
yield return e;
}
}
}
static void Main(string[] args)
{
string strTargetString = #"446408|0|1|111|446408|0|3|99884|111|73732|446408|0|0||";
foreach (var entry in Entry.parseList(strTargetString))
{
Console.WriteLine(
$#"Group:
Machine: {entry.MachineNr}
ControlDone: {entry.ControlDone}
Count: {entry.Count}
Items: {string.Join(", ",entry.Items)}");
}
}
}
There could be up to four items in my ListBox control. I want to assign the text displayed to string variables but I am running into problems with the index being out of range as soon as it gets to string Two. I know why this is happening (only one item in the listbox...) but I can't seem to get my head around how to do it.
I could possibly construct some kind of if statement to deal with this but I think there may be a more efficient method of doing it, rather than checking if it's less than 2 items, more than 1, etc.
Simple version of my code:
public void button1_Click(object sender, EventArgs e)
{
if (listBox1.Items.Count < 4) {
listBox1.Items.Add(comboBox1.Text);
} else {
System.Windows.Forms.MessageBox.Show("Too many");
}
string One = listBox1.Items[0].ToString();
string Two = listBox1.Items[1].ToString();
string Three = listBox1.Items[2].ToString();
string Four = listBox1.Items[3].ToString();
}
Note that I cannot use an array for this, as I need to access the variables in another application which does not have the ability to iterate through an array or access its indexes.
you could create a temporary array to handle the copying for you:
if (listBox1.Items.Count < 4) {
listBox1.Items.Add(comboBox1.Text);
} else {
System.Windows.Forms.MessageBox.Show("Too many");
}
string[] ListItemsArray= new string[4];
listBox1.Items.CopyTo(ListItemsArray, 0);
//Then you can leave this here:
string One = ListItemsArray[0] ?? "";
string Two = ListItemsArray[1] ?? "";
string Three = ListItemsArray[2] ?? "";
string Four = ListItemsArray[3] ?? "";
The listBox1.Items.CopyTo() method is explained here.
The ?? operator is used if you don't want any value to be null
If its really just up to 4 items, then manually knock it out?
string One = "";
string Two = "";
string Three = "";
string Four = "";
if (listBox1.Items.Count >= 1)
{
One = listBox1.Items[0];
}
if (listBox1.Items.Count >= 2)
{
Two = listBox1.Items[1];
}
if (listBox1.Items.Count >= 3)
{
Three = listBox1.Items[2];
}
if (listBox1.Items.Count >= 4)
{
Four = listBox1.Items[3];
}
Its not elegant, but the job is done.
You could use a for loop over the listBox.Items so you never try to access indices that are out of range.
You could first create an array of strings like so:
string[] names = new string[] { "", "", "", "" };
Then you could use a for loop over the items of the listbox and set the strings of the array of strings you just created to be equal to whatever is in the listBox[index].ToString() like:
for (int i = 0; i < listBox.Items.Count; i++)
{
names[i] = listBox.Items[i].ToString();
}
Finally, you set your original variables with the :
string one = names[0];
string two = names[1];
string three = names[2];
string four = names[3];
If any of the strings above is an empty string, it means you didn't have any item on that position in the listbox or the item you had in the listbox implements ToString() to return an empty string.
Not sure if I understood your problem, but I'd do something like that.
I am working on creating a windows form application and I have come across a problem. I am reading data in from the serial port.
string RxString = serialPort1.ReadExisting();
This works fine but what I now want to do is extract values from my RxString and put them into their own string arrays.
This the RxString format:
GPS:050.1347,N,00007.3612,WMAG:+231\r\n
it repeats itself as more data is added from the serial port the numbers change but stay the same length, and the + changes to -. I want to put the numbers between GPS: and ,N into one string array, the numbers between N, and ,W in another string array and finally the numbers between + and \r\n in a 3rd string array.
How would I go about doing this?
Ok, Regex solution:
string pattern = #"^GPS:(?<gps>.{8}),N,(?<n>.{10}),WMAG:(\+|\-)(?<wmag>.{3})\\r\\n$";
string gps = string.Empty;
string n = string.Empty;
string wmag = string.Empty;
string input = #"GPS:050.1347,N,00007.3612,WMAG:+231\r\n";
Regex regex = new Regex(pattern);
if (regex.IsMatch(input))
{
Match match = regex.Match(input);
foreach (Capture capture in match.Groups["gps"].Captures)
gps = capture.Value;
foreach (Capture capture in match.Groups["n"].Captures)
n = capture.Value;
foreach (Capture capture in match.Groups["wmag"].Captures)
wmag = capture.Value;
}
Console.Write("GPS: ");
Console.WriteLine(gps);
Console.Write("N: ");
Console.WriteLine(n);
Console.Write("WMAG: ");
Console.WriteLine(wmag);
Console.ReadLine();
Try this:
string RxString = serialPort1.ReadExisting();
string latitude = RxString.Split(',')[0].Substring(4);
string longitude = RxString.Split(',')[2];
string mag = RxString.Split(',')[3].Substring(6).Trim();
If the string is always the same length, the best way is to use substring() method.
I'm sure there's some RegEx that could make this prettier, but I'm not great at regex so I'd checkout C#'s String.Split function. Substring would work if you know the numbers will be the same length, but if that's not a guarantee, Split would be your best bet.
You could split each line on the comma, creating an array, then use Replace to remove the extra text (like GPS: and WMAG:), if you know that's going to be the same every time.
This is not the best solution since it uses "magic" numbers and substrings - but may work for your situation since you said the string length is always the same.
var serialPortInfo = "GPS:050.1347,N,00007.3612,WMAG:+231\r\n";
private List<string> value1 = new List<string>();
private List<string> value2 = new List<string>();
private List<string> value3 = new List<string>();
private void populateValues(string s)
{
// this should give an array of the following:
// values[0] = "050.1347"
// values[1] = "N"
// values[2] = "00007.3612"
// values[3] = "WMAG:+231"
//
var values = (s.Substring(4, (s.Length - 8))).Split(',');
// populate lists
//
value1.Add(values[0]);
value2.Add(values[2]);
value3.Add(values[3].Substring(6, 3));
}
//usage
populateValues(serialPortInfo);
I have a string 731478718861993983 and I want to get this 73-1478-7188-6199-3983 using C#. How can I format it like this ?
Thanks.
By using regex:
public static string FormatTest1(string num)
{
string formatPattern = #"(\d{2})(\d{4})(\d{4})(\d{4})(\d{4})";
return Regex.Replace(num, formatPattern, "$1-$2-$3-$4-$5");
}
// test
string test = FormatTest1("731478718861993983");
// test result: 73-1478-7188-6199-3983
If you're dealing with a long number, you can use a NumberFormatInfo to format it:
First, define your NumberFormatInfo (you may want additional parameters, these are the basic 3):
NumberFormatInfo format = new NumberFormatInfo();
format.NumberGroupSeparator = "-";
format.NumberGroupSizes = new[] { 4 };
format.NumberDecimalDigits = 0;
Next, you can use it on your numbers:
long number = 731478718861993983;
string formatted = number.ToString("n", format);
Console.WriteLine(formatted);
After all, .Net has very good globalization support - you're better served using it!
string s = "731478718861993983"
var newString = (string.Format("{0:##-####-####-####-####}", Convert.ToInt64(s));
LINQ-only one-liner:
var str = "731478718861993983";
var result =
new string(
str.ToCharArray().
Reverse(). // So that it will go over string right-to-left
Select((c, i) => new { #char = c, group = i / 4}). // Keep group number
Reverse(). // Restore original order
GroupBy(t => t.group). // Now do the actual grouping
Aggregate("", (s, grouping) => "-" + new string(
grouping.
Select(gr => gr.#char).
ToArray())).
ToArray()).
Trim('-');
This can handle strings of arbitrary lenghs.
Simple (and naive) extension method :
class Program
{
static void Main(string[] args)
{
Console.WriteLine("731478718861993983".InsertChar("-", 4));
}
}
static class Ext
{
public static string InsertChar(this string str, string c, int i)
{
for (int j = str.Length - i; j >= 0; j -= i)
{
str = str.Insert(j, c);
}
return str;
}
}
If you're dealing strictly with a string, you can make a simple Regex.Replace, to capture each group of 4 digits:
string str = "731478718861993983";
str = Regex.Replace(str, "(?!^).{4}", "-$0" ,RegexOptions.RightToLeft);
Console.WriteLine(str);
Note the use of RegexOptions.RightToLeft, to start capturing from the right (so "12345" will be replaced to 1-2345, and not -12345), and the use of (?!^) to avoid adding a dash in the beginning.
You may want to capture only digits - a possible pattern then may be #"\B\d{4}".
string myString = 731478718861993983;
myString.Insert(2,"-");
myString.Insert(7,"-");
myString.Insert(13,"-");
myString.Insert(18,"-");
My first thought is:
String s = "731478718861993983";
s = s.Insert(3,"-");
s = s.Insert(8,"-");
s = s.Insert(13,"-");
s = s.Insert(18,"-");
(don't remember if index is zero-based, in which case you should use my values -1)
but there is probably some easier way to do this...
If the position of "-" is always the same then you can try
string s = "731478718861993983";
s = s.Insert(2, "-");
s = s.Insert(7, "-");
s = s.Insert(12, "-");
s = s.Insert(17, "-");
Here's how I'd do it; it'll only work if you're storing the numbers as something which isn't a string as they're not able to be used with format strings.
string numbers = "731478718861993983";
string formattedNumbers = String.Format("{0:##-####-####-####-####}", long.Parse(numbers));
Edit: amended code, since you said they were held as a string in your your original question