I have a list as a single string like - "['2','4','5','1']" and length of this is 17 as each char is counted.
Now I want to parse it into list object like - ['2','4','5','1'] whose length will be 4 as the number of elements in a list.
How can I do this in C#?
Can it be done without doing basic string operations? If yes then how?
Without basing string operations
Your string value looks like valid JSON array.
using Newtonsoft.Json;
var list = JsonConvert.DeserializeObject<List<char>>("['2','4','5','1']");
// => ['2','4','5','1']
If you need output as integers set output type to be list of integers and JSON serializer will convert it to integers.
var list = JsonConvert.DeserializeObject<List<int>>("['2','4','5','1']");
// => [2, 4, 5, 1]
Converting to integers will handle negative values as well ;)
var list = JsonConvert.DeserializeObject<List<int>>("['-2','4','-5','1']");
// => [-2, 4, -5, 1]
You can try regular expressions and Linq in order to Match all the integers and turn them (ToList()) into List<int>:
using System.Linq;
using System.Text.RegularExpressions;
...
string str = "['2','4','5','1']";
var result = Regex
.Matches(str, #"\-?[0-9]+") // \-? for negative numbers
.Cast<Match>()
.Select(match => int.Parse(match.Value)) // int.Parse if you want int, not string
.ToList();
Try to Split by , and then use Regex to get only digits:
var str = "['2','4','5','1']".Split(new char[] {',' })
.Select(s => Regex.Match(s, #"\d+").Value);
Or thanks to #Fildor :
var str = Regex.Matches("['2','4','5','1']", #"\d+").Cast<Match>()
.Select(s=> s.Value);
Related
I have a string and I want to split the string after every 2nd comma. Is this doable using split string in c#?
Example string:
"This,is,an, example,for,the,stackoverflow,community"
Desired output
This,is
an,example
for,the
stackoverflow,community
Any help would be much appreciated thanks!
Using Enumerable.Chunk from .NET 6, you can
split on ",",
create chunks of two items each and
re-join those chunks:
string input = "This,is,an,example,for,the,stackoverflow,community";
var output = input.Split(",")
.Chunk(2)
.Select(chunk => string.Join(",", chunk));
foreach (string s in output)
Console.WriteLine(s);
fiddle
If you're stuck with the "classic" .NET Framework, here are chunk implementations for .NET < 6:
how do I chunk an enumerable?
You could do something like this:
var s = "This,is,an, example,for, the, stackoverflow, community";
var a = ("," + s + ",").Split(',');
// requires using System.Linq;
var b = Enumerable.Range(0, a.Length / 2)
.Select(i => $"{a[2 * i]}, {a[2 * i + 1]}".Trim(',', ' '));
Range enumerates the resulting array and computes concatenations of the corresponding pairs of strings.
You could also use a pattern to match 1 or more characters except for a comma using a negated character class [^,]+ before and after the comma:
string pattern = #"[^,]+,[^,]+";
string input = "This,is,an, example,for,the,stackoverflow,community";
foreach (Match m in Regex.Matches(input, pattern))
{
Console.WriteLine(m.Value);
}
Output
This,is
an, example
for,the
stackoverflow,community
I'm trying to filter only digits in string array. This works if I have this array:
12324 asddd 123 123, but if I have chars and digits in one string e.g. asd1234, it does not take it.
Can u help me how to do it ?
int[] result = input
.Where(x => x.All(char.IsDigit))// tried with .Any(), .TakeWhile() and .SkipWhile()
.Select(int.Parse)
.Where(x => x % 2 == 0)
.ToArray();
Something like this should work. The function digitString will select only digits from the input string, and recombine into a new string. The rest is simple, just predicates selecting non-empty strings and even numbers.
var values = new[]
{
"helloworld",
"hello2",
"4",
"hello123world123"
};
bool isEven(int i) => i % 2 == 0;
bool notEmpty(string s) => s.Length > 0;
string digitString(string s) => new string(s.Where(char.IsDigit).ToArray());
var valuesFiltered = values
.Select(digitString)
.Where(notEmpty)
.Select(int.Parse)
.Where(isEven)
.ToArray();
You need to do it in 2 steps: First filter out all the invalid strings, then filter out all the non-digits in the valid strings.
A helper Method would be very readable here, but it is also possible with pure LINQ:
var input = new[]{ "123d", "12e", "pp", "33z3"};
input
.Where(x => x.Any(char.IsDigit))
.Select(str => string.Concat(str.Where(char.IsDigit)));
Possible null values should be drop to avoid NullReferenceException.
string.Join() suitable for concatenation with digit filtering.
Additinally empty texts should be dropped because it cannot be converted to an integer.
string[] input = new string[] { "1234", "asd124", "2345", "2346", null, "", "asdfas", "2" };
int[] result = input
.Where(s => s != null)
.Select(s => string.Join("", s.Where(char.IsDigit)))
.Where(s => s != string.Empty)
.Select(int.Parse)
.Where(x => x % 2 == 0)
.ToArray();
Using Linq Aggregate method and TryParse() can give you perfect result:
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
var input = new string[] { "aaa123aaa124", "aa", "778", "a777", null };
var result = input.Aggregate(
new List<int>(),
(x, y) =>
{
if (y is null)
return x;
var digitOnlyString = Regex.Replace(y, "[^0-9]", string.Empty);
if (int.TryParse(digitOnlyString, out var temp) && temp % 2 == 0)
x.Add(temp);
return x;
})
.ToArray();
Max,
You can do this in a single expression like so:
using System.Linq;
using System.Text.RegularExpressions;
var input = new[] { "aaa123aaa124", "aa", "778", "a777", null };
var rx = new Regex(#"[0-9]+");
var numbersOnly = input.Where(s => !string.IsNullOrEmpty(s) && rx.IsMatch(s))
.Select(s => string.Join("", rx.Matches(s).Cast<Match>().Select(m => m.Value)));
foreach (var number in numbersOnly) Console.WriteLine(number);
Which returns:
123124
778
777
if I have chars and digits in one string e.g. asd1234, it does not take it
Apparently you want to parse this line also. You want to translate "asd1234" to "1234" and then parse it.
But what if your input sequence of strings contains a string with two numbers: "123asd456". Do you want to interpret this as "123", or maybe as "123456", or maybe you consider this as two numbers "123" and "456".
Let's assume you don't have this problem: every string contains at utmost one number, or if you have a string with more than one number, you only want the first number.
In fact, you only want to keep those string that are "zero or more non-digits followed by one or more digits followed by zero or more characters.
Enter Regular Expressions!
const string regexTxt = "\D*\d+.*";
Regex regex = new Regex(regexTxt);
\D: any non-digit
*: zero or more
\d: any digit
+: one or more
. any character
(...) capture the parts between the parentheses
So this regular expression matches any string that starts with zero or more non-digits, followed by at least one digit, followed by zero or more characters. Capture the "at least one digit" part.
If you try to Match() an input string with this regular expression, you get a Match object. Property Success tells you whether the input string is according to the regular expression.
The Match object has a property Groups which contains all Matches. Groups[0] is the complete string, Groups1 contains a Group which has the first captured string in property Value.
A simple program that shows how to use the regular expression:
const string regexTxt = #"\D*(\d+).*";
Regex regex = new Regex(regexTxt);
var lines = new string[]
{
String.Empty,
"A",
"A lot of text, no numbers",
"1",
"123456",
"Some text and then a number 123",
"Several characters, then a number: 123 followed by another number 456!",
"___123---456...",
};
foreach (var line in lines)
{
Match match = regex.Match(line);
if (match.Success)
{
string capturedDigits = match.Groups[1].Value;
int capturedNumber = Int32.Parse(capturedDigits);
Console.WriteLine("{0} => {1}", line, capturedNumber);
}
}
Or in a LINQ statement:
const string regexTxt = #"\D*(\d+).*";
Regex regex = new Regex(regexTxt);
IEnumerable<string> sourceLines = ...
var numbers= sourceLines
.Select(line => regex.Match(line)) // Match the Regex
.Where(match => match.IsMatch) // Keep only the Matches that match
.Select(match => Int32.Parse(match.Groups[1].Value);
// Finally Parse the captured text to int
I am very new to programming and I have a question, I am trying to use Regex method to extract hours, minutes and seconds from a string and putting them into an array, but so far I can do it with only one number:
int initialDay D = 0;
string startDay = Console.ReadLine(); //input: "It started 5 days ago"
var resultString = Regex.Match(startDay, #"\d+").Value;
initialDay = Int32.Parse(resultString); // initialDay here equals 5.
How do manage to read from a string 06: 11: 33, and transform these hours, minutes and seconds into an array of ints? So the resulting array would be like this:
int[] array = new int[] {n1, n2, n3}; // the n1 would be 6, n2 would be 11 and n3 would be 33
Thank you for your time in advance!
If the input is in this format (dd:dd:dd), you actually don't need regex in this. You can use String.Split() method. For example:
string test = "23:22:21";
string []res = test.Split(':');
The res array will now contains "23", "22", "21" as its elements. You just then need to convert them into int.
Unless you are trying to learn regular expressions, there is no reason for you to perform this parsing yourself.
Use TimeSpan.Parse() method for this task.
You could use string.Split() to get an array of elements separated by :. Then you can loop through it, int.Parse the elements and assign them to the integer array.
string[] buffer = startDay.Split(':');
int[] array = new int[buffer.Length];
for (int i = 0; i < buffer.Length; i++)
{
array[i] = int.Parse(buffer[i]);
}
Or you can use Linq's Select() to do the parsing.
int[] array = startDay.Split(':').Select(e => int.Parse(e)).ToArray();
Use Regex.Matches(string input, string pattern) like this:
var results = Regex.Matches(startDay, #"\d+");
var array = (from Match match in results
select Convert.ToInt32(match.Value))
.ToArray();
Instead regular expression, you can use TimeSpan.Parse()
Check it https://learn.microsoft.com/pl-pl/dotnet/api/system.timespan.parse?view=netframework-4.8
RegEx way:
var pattern = #"(\d{1,2})\s?\:\s?(\d{1,2})\s?\:\s?(\d{1,2})";
var input = "06 : 11 : 33";
var arr = Regex.Matches(input, pattern)
.Cast<Match>()
.SelectMany(x => x.Groups.Cast<Group>()
.Skip(1)
.Select(y => int.Parse(y.Value)))
.ToArray();
Console.WriteLine(string.Join("\n", arr));
The output:
06
11
33
regex101
If you have date as simple string you can use split method:
string dataString = "06 : 11 : 33";
string[] arrayStr = dataString.Split(':');
Then you can make int list using System.Linq:
List<int> intList = arrayStr.Select(p => Convert.ToInt32(p)).ToList();
How could I get the last three digits of this string?
var myString = "77441-Megrhfj654JHK";
You can try regular expressions to get last exactly 3 digits in a row:
using System.Text.RegularExpressions;
...
var myString = "77441-Megrhfj654JHK";
// Exactly 3 digits while start matching from the right
string digits = Regex.Match(myString, "[0-9]{3}", RegexOptions.RightToLeft).Value;
Console.WriteLine(digits);
Outcome:
654
Very straight forward LINQ example
public static class StringExtensions
{
public static string GetLastDigits( this string source, int count )
{
return new string( source
.Where(ch => Char.IsDigit(ch))
.Reverse()
.Take(count)
.Reverse()
.ToArray());
}
}
See working example on .net fiddle
In C# 8, you can use a range: myString[^3..];
Assuming that the input string is in a fixed format:
var lastThree = myString[^6..^3];
Or, in older C# versions:
var lastThree = myString.Substring(13, 3);
For just the last three numeric digits anywhere, something like:
var digits = new string(myString.Where(char.IsDigit).ToArray());
var lastThree = digits[^3..];
var myString = "77441-Megrhfj654JHK";
var digits = Regex.Match(myString, "[0-9]").Value;
return digits.Substring(Math.Max(digits.Length - 3,0));
I have a string of the following format:
0Days0hours51Minutes32Seconds
What I would like to do is split that into the 4 numerical values for
days,hours,minutes,seconds
So the values I would need back are 0, 0, 51, 32.
Are there any better ways of doing this the usual string.Split(...) method?
Ideally if there is a split by letters, so that only the numerical values remain.
string input = "0Days0hours51Minutes32Seconds";
var nums = Regex.Matches(input, #"\d+").Cast<Match>()
.Select(m => int.Parse(m.Value))
.ToList();
Instead of using String.Split(...) you could use Regex.Match(string,#"\d+") to retrieve only the numerical values.
var numbers = Regex.Split(input, #"\D+");
If you just want the numbers and don't care about the rest of the string, you can use:
string input = "0Days0hours51Minutes32Seconds";
var numbers = Regex.Matches(input, #"\d+")
.Cast<Match>()
.Select(m => int.Parse(m.Value));
However, if you want to validate the string conforms to the expected format, you could use a more comprehensive pattern.
string input = "0Days0hours51Minutes32Seconds";
var match = Regex.Match(
input,
"^(\d+)Days(\d+)hours(\d+)Minutes(\d+)Seconds$");
var days = int.Parse(match.Groups[1].Value);
var hours = int.Parse(match.Groups[2].Value);
var minutes = int.Parse(match.Groups[3].Value);
var seconds = int.Parse(match.Groups[4].Value);
I would also suggest you put these values into a useful structure like TimeSpan:
var timespan = new TimeSpan(days, hours, minutes, seconds);