How to search string not in char array using LinQ - c#

List<string> words = new List<string> { "abc", "acb", "cba", "cb a", "abf", "sea", "aba", "so ap", "a b c" };
string allowedChars = "abc";
I want to check invalid charachters in list string. I try use IndexOfAny() but IndexOfAny() does not check white space. How to check string which contains invalid charachters?
The result I want: "cb a", "abf", "sea", "so ap", "a b c"

var invalid = words.Where(w => !w.All(allowedChars.Contains));
It checks for every word if there is at least one char in it which is not contained in allowedChars.
This is the same but little bit more verbose:
var invalid = words.Where(w => w.Any(c => !allowedChars.Contains(c)));
Both stop execution if they found the first char that is not contained.
As Juharr has noted, if there are many characters allowed you could make it more efficient by using a HashSet<char> instead of the String:
var alloweCharSet = new HashSet<char>(allowedChars);

Returns all words that contain any other characters than allowedChars:
var result = words.Where(w => w.Except(allowedChars).Any());
While this gives the desired result, it was pointed out that this will, by calling Except, create a new Set for allowedChars for every word in the list. This might not give the best performance.

Related

LINQ: Null checking in string.Format()

I have a requirement to get the first letter of the first, middle and last names. It is working if each of the fields contain value. But the middle name is nullable field. So i'm getting error if the value of middle name is null.
(from P in this._dbContext.Person
where P.PersonIndex == personIndex
select new PersonInitialsDTO
{
PersonIndex = P.PersonIndex,
PersonInitials = string.Format("{0}{1}{2}", P.FirstName.ToUpper().First(), P.MiddleName.ToUpper().First(), P.LastName.ToUpper().First())
}).FirstOrDefault();
use ? to see if the value is null before executing next methods.
string.Format("{0}{1}{2}", P.FirstName.ToUpper().First(), P.MiddleName?.ToUpper().First(), P.LastName.ToUpper().First())
P.MiddleName?.ToUpper().First() -> If P.MiddleName is null, dont do ToUpper() or any other methods afterwards.
Example of use of ?. in string.format statement.
Pers person = new Pers()
{
First = "First",
Last = "Last"
};
Console.WriteLine(string.Format("{0}{1}{2}", person.First.First(), person.Middle?.ToUpper().First(), person.Last.First()));
// Prints
FL
Requirement: get the first letter of the first, middle and last names.
Well, apparently this requirement is not complete: if one of these names is null or empty, there is no first letter.
Furthermore: if I look at the code, you don't want the first letter, you want a string that contains the first letter.
And why uppercase the complete string if you will only use the first character?
So let's change it slightly:
Requirement: Given three strings: first, middle and last, get me the string that contains the uppercase values of the first character of each of these strings, or String.Empty if the string is null or empty.
"Vincent" "van" "Gogh" => "VVG"
"rembrandt" "van" "rijn" => "RVR"
"Piet" "Mondriaan" => "PM"
From each of these three strings,
Check if if it is null, if so, use Enumerable.Empty<char>
Create a sequence that contains only the first character of the string. So if the string was null or empty, this first character will be an empty sequence of character).
Concatenate these three sequences.
Result: a sequence of characters that contains only the first character of each of these strings, or no character at all if the string was null or empty.
In baby steps, I'll write the type in front, so you can see what happens.
string first = ...
string middle = ...
string last = ...
IEnumerable<char> firstChars = first?.Take(1) ?? Enumerable.Empty<char>(),
IEnumerable<char> midChars = middle?.Take(1) ?? Enumerable.Empty<char>(),
IEnumerable<char> lastChars = last?.Take(1) ?? Enumerable.Empty<char>(),
IEnumerable<char> chars = firstChars.Concat(midChars).Concat(lastChars);
So from our original input examples we have:
Vincent Van Gogh: {'V', 'V', 'G'}
rembrandt van rijn: {'r', 'v', 'r'}
Piet Mondriaan {'p', 'm'}
So all we have to do is to convert them to uppercase and convert to a string:
IEnumerable uppercaseChars = chars.Select(c => Char.ToUpper(c));
Note: until know the query is not executed! I only used methods that use deferred execution!
string result = new string(uppercaseChars.ToArray());
Of course you can write this in one big LINQ statement. I'm not sure if that would improve readability. It won't have any effect on performance.
I tried with below. Now it's working
(from P in this._dbContext.Person
where P.PersonIndex == personIndex
select new PersonInitialsDTO
{
PersonIndex = P.PersonIndex,
PersonInitials = (P.MiddleName == "")
? string.Format("{0}{1}", P.FirstName.ToUpper().First(),
P.LastName.ToUpper().First())
: string.Format("{0}{1}{2}", P.FirstName.ToUpper().First(),
P.MiddleName.ToUpper().First(), P.LastName.ToUpper().First())
}).FirstOrDefault();

Convert String to Byte Array replacing characters between specific character

I am trying to find a way to convert a string (entered into a TextBox) and convert it to a byte array to send out a serial port / socket.
I am fine with the converting string to byte[] part but am struggling a bit with the replacement
Essentially the GUI allows the user to specific the format of the response to send and I was looking at something like the following :-
User Enters : [2] Test {1} {2} [3]
{1} and {2} are variable fields which can be pulled from the incoming message so they are currently being replaced without issue.
What I am trying to achieve is replace the [2] with an STX character and the [3] with an ETX character with the 2 and 3 being their ASCII equivalents. www.asciitable.com
The user can enter any valid ascii character in this format so [13] for CR etc
Would the best way to loop through the string remembering the index of [ and then the index of ] and grab all characters between these two indexes? Or is there a more efficient way?
Thanks,
Daniel.
A regular expression can find digits between brackets and replace them with a calculated value.
Your replacement scheme looks like it might be similar to String.Format but you'll have to compare that and decide on the order of operations and meaning of special characters.
The encoding will throw an exception if the bracketed number is outside of 0-127. You could have some other behavior if you want.
var encoding = Encoding.GetEncoding(Encoding.ASCII.CodePage,
EncoderFallback.ExceptionFallback,
DecoderFallback.ExceptionFallback);
var bracketRegex = new Regex(#"\[(?<digits>\d+)\]", RegexOptions.Compiled);
MatchEvaluator convertToCodepoint = (match) =>
Char.ConvertFromUtf32(Int32.Parse(match.Groups["digits"].Value));
var values = new[] {"a", "b", "c" };
var input = "[2] Test {1} {2} [3]";
encoding.GetBytes(String.Format(bracketRegex.Replace(input, convertToCodepoint), values))
.Dump();
I think you should write a code similar to this:
string input = TextBox.text; "User name (sales)";
//Use those lines if you don't know how many times do you have to iterate.
var totalOfBraces = input.Where(x => x == '{').Count();
var totalOfBrackets = input.Where(x => x == '[').Count();
var totalOfElements = totalOfBraces + totalOfBrackets;
string output = input.Split('[', ']')[1];
string output = input.Split('{', '}')[1];
And you you can get the elements between Braces and Brackets and do a replace of them.
Then, why I added totalOfElements, to have the possibility to do a for bucle
For example:
var counterOfBraces = 0;
var counterOfBrackets = 0;
for(var i=0; i<totalOfElements.Count(); i++){
if(i < totalOfBrackets){
counterOfBrackets+=1;
var textToFind = "[" + index + "]";
input = input.Replace(textToFind, "some new text");
} else {
//Do the same for braces
}
}
//NOW HERE, YOU HAVE YOUR TEXT FORMATED AND READY TO CONVERT IT TO BYTE[]

Parse multiple values from string c#

Suppose I have written "5 and 6" or "5+6". How can I assign 5 and 6 to two different variables in c# ?
P.S. I also want to do certain work if certain chars are found in string. Suppose I have written 5+5. Will this code do that ?
if(string.Contains("+"))
{
sum=x+y;
}
string input="5+5";
var numbers = Regex.Matches(input, #"\d+")
.Cast<Match>()
.Select(m => m.Value)
.ToList();
Personally, I would vote against doing some splitting and regular expression stuff.
Instead I would (and did in the past) use one of the many Expression Evaluation libraries, like e.g. this one over at Code Project (and the updated version over at CodePlex).
Using the parser/tool above, you could do things like:
A simple expression evaluation then could look like:
Expression e = new Expression("5 + 6");
Debug.Assert(11 == e.Evaluate());
To me this is much more error-proof than doing the parsing all by myself, including regular expressions and the like.
You should use another name for your string than string
var numbers = yourString.Split("+");
var sum = Convert.ToInt32(numbers[0]) + Convert.ToInt32(numbers[1]);
Note: Thats an implementation without any error checking or error handling...
If you want to assign numbers from string to variables, you will have to parse string and make conversion.
Simple example, if you have text with only one number
string text = "500";
int num = int.Parse(text);
Now, if you want to parse something more complicated, you can use split() and/or regex to get all numbers and operators between them. Than you just iterate array and assign numbers to variables.
string text = "500+400";
if (text.Contains("+"))
{
String[] data = text.Split("+");
int a = int.Parse(data[0]);
int b = int.Parse(data[1]);
int res = a + b;
}
Basicly, if you have just 2 numbers and operazor between them, its ok. If you want to make "calculator" you will need something more, like Binary Trees or Stack.
Use the String.Split method. It splits your string rom the given character and returns a string array containing the value that is broken down into multiple pieces depending on the character to break, in this case, its "+".
int x = 0;
int y = 0;
int z = 0;
string value = "5+6";
if (value.Contains("+"))
{
string[] returnedArray = value.Split('+');
x = Convert.ToInt32(returnedArray[0]);
y = Convert.ToInt32(returnedArray[1]);
z = x + y;
}
Something like this may helpful
string strMy = "5&6";
char[] arr = strMy.ToCharArray();
List<int> list = new List<int>();
foreach (char item in arr)
{
int value;
if (int.TryParse(item.ToString(), out value))
{
list.Add(item);
}
}
list will contains all the integer values
You can use String.Split method like;
string s = "5 and 6";
string[] a = s.Split(new string[] { "and", "+" }, StringSplitOptions.RemoveEmptyEntries);
Console.WriteLine(a[0].Trim());
Console.WriteLine(a[1].Trim());
Here is a DEMO.
Use regex to get those value and then switch on the operand to do the calculation
string str = "51 + 6";
str = str.Replace(" ", "");
Regex regex = new Regex(#"(?<rightHand>\d+)(?<operand>\+|and)(?<leftHand>\d+)");
var match = regex.Match(str);
int rightHand = int.Parse(match.Groups["rightHand"].Value);
int leftHand = int.Parse(match.Groups["leftHand"].Value);
string op = match.Groups["operand"].Value;
switch (op)
{
case "+":
.
.
.
}
Split function maybe is comfortable in use but it is space inefficient
because it needs array of strings
Maybe Trim(), IndexOf(), Substring() can replace Split() function

C# how to split a string backwards?

What i'm trying to do is split a string backwards. Meaning right to left.
string startingString = "<span class=\"address\">Hoopeston,, IL 60942</span><br>"
What I would do normally is this.
string[] splitStarting = startingString.Split('>');
so my splitStarting[1] would = "Hoopeston,, IL 60942</span"
then I would do
string[] splitAgain = splitStarting[1].Split('<');
so splitAgain[0] would = "Hoopeston,, IL 60942"
Now this is what I want to do, I want to split by ' ' (a space) reversed for the last 2 instances of ' '.
For example my array would come back like so:
[0]="60942"
[1]="IL"
[2] = "Hoopeston,,"
To make this even harder I only ever want the first two reverse splits, so normally I would do something like this
string[] splitCity,Zip = splitAgain[0].Split(new char[] { ' ' }, 3);
but how would you do that backwards? The reason for that is, is because it could be a two name city so an extra ' ' would break the city name.
Regular expression with named groups to make things so much simpler. No need to reverse strings. Just pluck out what you want.
var pattern = #">(?<city>.*) (?<state>.*) (?<zip>.*?)<";
var expression = new Regex(pattern);
Match m = expression .Match(startingString);
if(m.success){
Console.WriteLine("Zip: " + m.Groups["zip"].Value);
Console.WriteLine("State: " + m.Groups["state"].Value);
Console.WriteLine("City: " + m.Groups["city"].Value);
}
Should give the following results:
Found 1 match:
1. >Las Vegas,, IL 60942< has 3 groups:
1. Las Vegas,, (city)
2. IL (state)
3. 60942 (zip)
String literals for use in programs:
C#
#">(?<city>.*) (?<state>.*) (?<zip>.*?)<"
One possible solution - not optimal but easy to code - is to reverse the string, then to split that string using the "normal" function, then to reverse each of the individual split parts.
Another possible solution is to use regular expressions instead.
I think you should do it like this:
var s = splitAgain[0];
var zipCodeStart = s.LastIndexOf(' ');
var zipCode = s.Substring(zipCodeStart + 1);
s = s.Substring(0, zipCodeStart);
var stateStart = s.LastIndexOf(' ');
var state = s.Substring(stateStart + 1);
var city = s.Substring(0, stateStart );
var result = new [] {zipCode, state, city};
Result will contain what you requested.
If Split could do everything there would be so many overloads that it would become confusing.
Don't use split, just custom code it with substrings and lastIndexOf.
string str = "Hoopeston,, IL 60942";
string[] parts = new string[3];
int place = str.LastIndexOf(' ');
parts[0] = str.Substring(place+1);
int place2 = str.LastIndexOf(' ',place-1);
parts[1] = str.Substring(place2 + 1, place - place2 -1);
parts[2] = str.Substring(0, place2);
You can use a regular expression to get the three parts of the string inside the tag, and use LINQ extensions to get the strings in the right order.
Example:
string startingString = "<span class=\"address\">East St Louis,, IL 60942</span><br>";
string[] city =
Regex.Match(startingString, #"^.+>(.+) (\S+) (\S+?)<.+$")
.Groups.Cast<Group>().Skip(1)
.Select(g => g.Value)
.Reverse().ToArray();
Console.WriteLine(city[0]);
Console.WriteLine(city[1]);
Console.WriteLine(city[2]);
Output:
60942
IL
East St Louis,,
How about
using System.Linq
...
splitAgain[0].Split(' ').Reverse().ToArray()
-edit-
ok missed the last part about multi word cites, you can still use linq though:
splitAgain[0].Split(' ').Reverse().Take(2).ToArray()
would get you the
[0]="60942"
[1]="IL"
The city would not be included here though, you could still do the whole thing in one statement but it would be a little messy:
var elements = splitAgain[0].Split(' ');
var result = elements
.Reverse()
.Take(2)
.Concat( new[ ] { String.Join( " " , elements.Take( elements.Length - 2 ).ToArray( ) ) } )
.ToArray();
So we're
Splitting the string,
Reversing it,
Taking the two first elements (the last two originally)
Then we make a new array with a single string element, and make that string from the original array of elements minus the last 2 elements (Zip and postal code)
As i said, a litle messy, but it will get you the array you want. if you dont need it to be an array of that format you could obviously simplfy the above code a little bit.
you could also do:
var result = new[ ]{
elements[elements.Length - 1], //last element
elements[elements.Length - 2], //second to last
String.Join( " " , elements.Take( elements.Length - 2 ).ToArray( ) ) //rebuild original string - 2 last elements
};
At first I thought you should use Array.Reverse() method, but I see now that it is the splitting on the ' ' (space) that is the issue.
Your first value could have a space in it (ie "New York"), so you dont want to split on spaces.
If you know the string is only ever going to have 3 values in it, then you could use String.LastIndexOf(" ") and then use String.SubString() to trim that off and then do the same again to find the middle value and then you will be left with the first value, with or without spaces.
Was facing similar issue with audio FileName conventions.
Followed this way: String to Array conversion, reverse and split, and reverse each part back to normal.
char[] addressInCharArray = fullAddress.ToCharArray();
Array.Reverse(addressInCharArray);
string[] parts = (new string(addressInCharArray)).Split(new char[] { ' ' }, 3);
string[] subAddress = new string[parts.Length];
int j = 0;
foreach (string part in parts)
{
addressInCharArray = part.ToCharArray();
Array.Reverse(addressInCharArray);
subAddress[j++] = new string(addressInCharArray);
}

substring with linq?

I've got collection of words, and i wanna create collection from this collection limited to 5 chars
Input:
Car
Collection
Limited
stackoverflow
Output:
car
colle
limit
stack
word.Substring(0,5) throws exception (length)
word.Take(10) is not good idea, too...
Any good ideas ??
LINQ to objects for this scenario? You can do a select as in this:
from w in words
select new
{
Word = (w.Length > 5) ? w.Substring(0, 5) : w
};
Essentially, ?: gets you around this issue.
var words = new [] { "Car", "Collection", "Limited", "stackoverflow" };
IEnumerable<string> cropped = words.Select(word =>
word[0..Math.Min(5, word.Length)]);
Ranges are available in C# 8, otherwise you'll need to do:
IEnumerable<string> cropped = words.Select(word =>
word.Substring(0, Math.Min(5, word.Length)));
Something you can do, is
string partialText = text.Substring(0, Math.Min(text.Length, 5));
I believe the kind of answer you were looking for would look like this:
var x = new string[] {"car", "Collection", "Limited", "stackoverflow" };
var output = x.Select(word => String.Join("", word.Take(5).ToList()));
The variable "output" contains the result:
car
Colle
Limit
stack
and the string "car" doesn't throw an exception.
But while Join and Take(5) works, it's generally much simpler to use, as was suggested in another answer,
subString = word.Substring(0,Math.Min(5,word.Length));
The latter code is more human-readable and lightweight, though there is definitely a slight coolness factor to using Linq on a string to take the first five characters, without having to check the length of the string.

Categories