Get Group of Numbers on a String - c#

I have a string which consists of numbers and letters like the example below:
string strFood = "123d 4hello12";
What I want to accomplish is get all the group of numbers which is 123, 4, and 12.
I am trying to do this via LinQ but I am not getting the array results since my plan is to get the array then add them altogether which is 123 + 4 + 12 and the result is 139.
This is what I tried so far but this doesn't result to group of string or integer:
string[] strArr =
strFood .GroupBy(y => Char.IsDigit(y)).Select(y => y.ToString()).ToArray();
I also tried this one but this returns all the number in one string:
var foo = from a in strFood .ToCharArray() where Char.IsDigit(a) == true select a;
Any help would be appreciated.

I suggest using regular expressions to find all groups (matches) with aggregation via Linq:
string strFood = "123d 4hello12";
var sum = Regex
.Matches(strFood, "[0-9]+") // groups of integer numbers
.OfType<Match>()
.Select(match => int.Parse(match.Value)) // treat each group as integer
.Sum(); // sum up
If you want to obtain an array (and sum up later):
int[] result = Regex
.Matches(strFood, "[0-9]+") // groups of integer numbers
.OfType<Match>()
.Select(match => int.Parse(match.Value))
.ToArray();
...
var sum = result.Sum();

You could split your string to integers collection:
string strFood = "123d 4hello12";
var integers = new Regex(#"\D").Split(strFood)
.Where(x=>!string.IsNullOrWhiteSpace(x))
.Select(x=>int.Parse(x));
and after that sum it with:
var sum = integers.Sum(); // Result : 139
Edit after comment of #Dmitry Bychenko: with some characters, such as persian digits that won't work.
Solution: either use
new Regex(#"[^0-9+]")
or
new Regex(#"\D", RegexOptions.ECMAScript)

Just to add decimal numbers in summation, you can use this regex instead:
var str = "123d 4hello12and0.2plus.1and-1and2+8.but 1....1 a.b";
// ^^^ ^ ^^ ^^^ ^^ ^^ ^ ^ ^ ^^
var s = Regex
.Matches(str, #"-?([0-9]+|[0-9]*\.[0-9]+)")
.OfType<Match>()
.Sum(c=> double.Parse(c.Value, CultureInfo.InvariantCulture));
Result will be:
Count = 11
[0]: {123}
[1]: {4}
[2]: {12}
[3]: {0}
[4]: {.2}
[5]: {.1}
[6]: {-1}
[7]: {2}
[8]: {8}
[9]: {1}
[10]: {.1}
Sum = 149.39999999999998 //~= 149.4

var yourSum = strFood.Where(x=>Char.IsDigit(x)).Select(x=>Convert.ToInt32(x)).Sum()
This will give you the sum of all numbers in your string.
If you want just an IEnumerable of ints remove the Sum() from the end

Why don't you use a simple regular expression?
string input = "123d 4hello12";
int sum = System.Text.RegularExpressions.Regex.Matches(input, #"\d+").Cast<System.Text.RegularExpressions.Match>().Sum(m => Convert.ToInt32(m.Value));

I tried using an approach using Split and Join.
First i use Linq Select to replace non digits with a ',':
strFood.Select(ch => (Char.IsDigit(ch)) ? ch : ',');
I then use Join to turn this back into a string of the form "123,,4,,,,,12", I then Split this on "," and filter out values (using Where) which have an empty string, I then convert the string into a number e.g. "123" becomes 123 and I sum the array.
Putting this all together becomes:
var Sum = String.Join("",(strFood.Select(c => (Char.IsDigit(c)) ? c : ',')))
.Split(',').Where(c => c != "").Select(c => int.Parse(c)).Sum();
Here's a slightly shorter version using Concat:
var Sum = String.Concat(strFood.Select(ch => (Char.IsDigit(ch)) ? ch : ','))
.Split(',').Where(c => c != "").Select(c => int.Parse(c)).Sum();
This gives a result of 139

Try this:
int[] strArr = strFood.ToCharArray().Where(x=> Char.IsDigit(x)).Select(y => Convert.ToInt32(y.ToString())).ToArray();

Related

LINQ - find between lowest and highest string

I would like to find string numbers between "0000" and "9999" inside larger strings
from "qwt0000abc" to "qwt9999abc".
MSSQL where id between "qwt0000abc" and "qwt9999abc"
How I would write the same LINQ query?
var selectedOrders = orders.Where(f => f.Id between "qwt0000abc" and "qwt9999abc");
Assuming you only want rows with that same prefix and suffix, then just replace between like this:
var selectedOrders = orders.Where(f => f.Id.CompareTo("qwt0000abc") >= 0 && f.Id.CompareTo("qwt9999abc") < 0).ToList() ;
And if this is EF you can perhaps use Like:
var selectedOrders = orders.Where(f => EF.Functions.Like(f.Id, "qwt[0-9][0-9][0-9]abc")).ToList();
Try this:
var selectedOrders = arr.Where(x => Regex.IsMatch(x, ".*[0-9]{4}.*"));
or this, if you need exactly qwt prefix and abc suffix.
var selectedOrders = arr.Where(x => Regex.IsMatch(x, "qwt[0-9]{4}abc"));
.* here is any literal any number of times(include zero), [0-9]{4} is digit between 0 and 9, exactly 4 digits.

Reading double Numbers from a text file which contains string and number mixed

I have a file which contains Numbers and Texts. and I'm trying to read all numbers as double and put them in a one dimension double array.
In the file , some lines begin with Space. also some lines contain Two or Three numbers after each other.
The file is creating from another app which i don't want to change its output format.
The data in the file is like blow and some lines begin with some space :
110 ! R1
123.000753 ! Radian per s as R2
600.0451 65 ! j/kg
12000 ! 4 Number of iteration
87.619 ! (min 20 and max 1000)
My code so far is :
char[] splits = { ' ', '!' };
var array = File.ReadAllLines(#"myfile.dat")
.SelectMany(linee => linee.Split(splits))
.Where(n => !string.IsNullOrWhiteSpace(n.ToString()))
.Select(n =>
{
double doub;
bool suc = double.TryParse(n, out doub);
return new { doub, suc };
}).Where( values=>values.suc).ToArray();
The problem is that my code also read numbers after ! in the descriptions like line 4 and line 5.
Array have to be like this :
110 , 123.000735 , 6000.0451 , 65 , 120000 , 87.619
But in my code is like this :
110 , 123.000735 , 6000.0451 , 65 , 120000 , 4 , 87.619 , 20 , 1000
It's hard to give a general formula when given only a single example, but the following will work for your example:
return File.ReadLines(#"myfile.dat")
.Where(s => !String.IsNullOrWhiteSpace(s))
.Select(s => s.Substring(0, s.IndexOf('!')).Split(new [] {' '}, StringSplitOptions.RemoveEmptyEntries))
.SelectMany(s => s)
.Select(s => Double.Parse(s));
One approach could be as following.
var lines = str.Split(new []{"!",Environment.NewLine},StringSplitOptions.RemoveEmptyEntries)
.Where(x=> x.Split(new []{" "},StringSplitOptions.RemoveEmptyEntries).All(c=>double.TryParse(c, out _))).
SelectMany(x=> x.Split(new []{" "},StringSplitOptions.RemoveEmptyEntries).Select(c=>double.Parse(c)));
Here's an alternate solution using regular expressions:
var regex = new Regex(#"^(\s*(?<v>\d+(\.\d+)?)\s*)+\!.*$");
var query = from line in lines
let match = regex.Match(line)
where match.Success
from #group in match.Groups.Cast<Group>()
where #group.Name == "v"
select double.Parse(#group.Value, NumberStyles.Float, CultureInfo.InvariantCulture);

Create a dictionary from a string by separating the string using a word

Str = 7 X 4 # 70Hz LUVYG
I want to split the string with Hz
Key: 7 X 4 # 70Hz
Value: LUVYG
With the regular expression
^ - start of string
(.*) - zero or more characters (Groups[1])
\s - whitespace
(\S*) - zero or more non-whitespace characters (Groups[2])
$ - end of string
it is possible to split a string into 2 groups, using the last whitespace in the string as the delimiter.
Using this regular expression, you can use LINQ to process a collection of strings into a dictionary:
var unprocessed = new[] { "7 X 4 # 70Hz LUVYG" };
var dict =
unprocessed
.Select(w => Regex.Match(w, #"^(.*)\s(\S*)$"))
.Where(m => m.Success)
.ToDictionary(m => m.Groups[1].Value, m => m.Groups[2].Value);

Repeated character in pair using regex?

I have a list of numbers, and using regex that look like this (\d)(?=\d*\1)
Example list of numbers:
1234
5678
5565
5566
5567
5656
1212
Current Output using the expression:
5565
5566
5567
5656
1212
However, I want to extract list of numbers that are in 2 pairs in 4 numbers no matter what the arrangement is. For example: 1122, 1212, 2211, 2121, 1221, 2112
Example of Desired Output: (where 5565, 5567 is false)
5566
5656
1212
I am not familiar with regex, need some help.
If your numbers are always 4 digits you can do something like this
(?:(\d)(\d)\1\2)|(?:(\d)\3(\d)\4)|(?:(\d)(\d)\6\5)
So, if you have four digit numbers you can only have two different digits in each number. With \1 you can reference the first digit, with \2 the second, etc. This regex matches the three possible distributions: abab, abba and aabb.
Example: https://regex101.com/r/cP4nI5/2
Rather than Regex, if you want plain C# code, this will do
int number = 1212;
var isDoublePair = number.ToString()
.ToCharArray()
.GroupBy(c => c)
.Select(grp => grp.Count())
.All(count => count == 2);
As commented by w.b, this can be shortened to
var isDoublePair = number.ToString()
.GroupBy(c => c)
.All(g => g.Count() == 2);

How to format a number such that first 6 digits and last 4 digits are not hidden

How to format a number such that first 6 digits and last 4 digits are not hidden
such that 111111111111111 looks like 111111****1111
You can also use LINQ, substituting chars with indexes more than 5 and less than number.Length - 4 with *:
string number = "111111111111111";
string res = new string(number.Select((c, index) => { return (index <= 5 || index >= number.Length - 4) ? c : '*'; }).ToArray());
Console.WriteLine(res); // 111111*****1111
One simple way to do this is to slit the input..
int number = 111111111111111;
string firstsix = number.ToString().Substring(0,6) //gets the first 6 digits
string middlefour = number.ToString().Substring(6,4) //gets the next 4
string rest = number.ToString().Substring(10, number.ToString().Lenght) //gets the rest
string combined = firstsix + "****" +rest;
You need to use \G anchor in-order to do a continuous string match.
string result = Regex.Replace(str, #"(?:^(.{6})|\G).(?=.{4})", "$1*");
DEMO
IDEONE

Categories

Resources