Number of occurrences of a character in a string [duplicate] - c#

This question already has answers here:
How would you count occurrences of a string (actually a char) within a string?
(34 answers)
Closed 9 years ago.
I am trying to get the number of occurrences of a certain character such as & in the following string.
string test = "key1=value1&key2=value2&key3=value3";
How do I determine that there are 2 ampersands (&) in the above test string variable?

You could do this:
int count = test.Split('&').Length - 1;
Or with LINQ:
test.Count(x => x == '&');

Because LINQ can do everything...:
string test = "key1=value1&key2=value2&key3=value3";
var count = test.Where(x => x == '&').Count();
Or if you like, you can use the Count overload that takes a predicate :
var count = test.Count(x => x == '&');

The most straight forward, and most efficient, would be to simply loop through the characters in the string:
int cnt = 0;
foreach (char c in test) {
if (c == '&') cnt++;
}
You can use Linq extensions to make a simpler, and almost as efficient version. There is a bit more overhead, but it's still surprisingly close to the loop in performance:
int cnt = test.Count(c => c == '&');
Then there is the old Replace trick, however that is better suited for languages where looping is awkward (SQL) or slow (VBScript):
int cnt = test.Length - test.Replace("&", "").Length;

Why use regex for that. String implements IEnumerable<char>, so you can just use LINQ.
test.Count(c => c == '&')

Your string example looks like the query string part of a GET. If so, note that HttpContext has some help for you
int numberOfArgs = HttpContext.Current.QueryString.Count;
For more of what you can do with QueryString, see NameValueCollection

Here is the most inefficient way to get the count in all answers. But you'll get a Dictionary that contains key-value pairs as a bonus.
string test = "key1=value1&key2=value2&key3=value3";
var keyValues = Regex.Matches(test, #"([\w\d]+)=([\w\d]+)[&$]*")
.Cast<Match>()
.ToDictionary(m => m.Groups[1].Value, m => m.Groups[2].Value);
var count = keyValues.Count - 1;

Related

C# Regex: finding all matches of a number of patterns [duplicate]

This question already has answers here:
Getting overlapping regex matches in C#
(2 answers)
Closed 4 years ago.
I need help with a Regular Expression in C# which identifies how many predefined 3-letter strings appear in a string.
So, for example:
Regex.Matches("qwerty", #"(?i)(qwe|wer|ert|rty|tyu|yui|uio|iop|op\[|p\[\])")
Would return:
["qwe", "wer", "ert", "rty"]
(But of course the Regex above is incorrect!).
FYI, this is to check whether 3 consecutive characters on a keyboard appear in a password (in the case above "qwerty" is the password.
Thanks :)
EDIT 1: This needs to be case-insensitive.
You could use a positive lookahead
Regex.Matches("qwerty",#"(?i)(?=(qwe|wer|ert|rty|tyu|yui|uio|iop|op\[|p\[\])).")
Another Linq solution to achieve what I think you are looking for:
We split the input in chunk of Length
We check if our input contains any of the chunks
Try it Online!
public static bool ContainsAnySubstring(string predifined, int length, string input)
{
var sections = predifined.Remove(predifined.Length - length + 1).Select((_,i) => predifined.Substring(i, length));
return sections.Any(section => input.Contains(section));
}
public static void Main()
{
Console.WriteLine(ContainsAnySubstring("qwerty", 3, "azerty") == true);
Console.WriteLine(ContainsAnySubstring("qwerty", 5, "azerty") == false);
}
If you want to use US keyboard only (see s.m. comment) you can try Linq instead of Regex:
using System.Linq;
...
string source = "qwerty";
// either put chunks to test direct
string[] chunks = new string[] {
"qwe", "wer", "ert", "rty", "tuy", "yui", "uio", "iop", "op[", "p[]", "[]\\"};
// ...or generate them as 3-grams:
// string line = "qwertyuiop[]\\";
// string[] chunks = Enumerable
// .Range(0, line.Length + 1 - 3)
// .Select(start => line.Substring(start, 3))
// .ToArray();
string[] appeared = chunks
.Where(chunk => source.IndexOf(chunk, StringComparison.OrdinalIgnoreCase) >= 0)
.ToArray();
Console.Write(string.Join(", ", appeared));
Outcome:
qwe, wer, ert, rty
Instead of using regex, you can just take every substrings of the input and check if it is a substring of your keyboard layout:
IEnumerable<string> FindContinuousKeyInputs(string input, int length = 3)
{
if (length <= 0)
throw new ArgumentException(nameof(length));
if (input.Length < length)
return Enumerable.Empty<string>();
var rows = new string[]
{
#"qwertyuiop[]\",
"asdfghjkl;'",
"zxcvbnm,./"
};
return Enumerable.Range(0, input.Length - length + 1)
.Select(x => input.Substring(x, length))
.Where(x => rows.Any(y => y.Contains(x)));
}
For case insensitive, replace the last Where with this:
.Where(x => rows.Any(y => CultureInfo.InvariantCulture.CompareInfo.IndexOf(y, x, CompareOptions.IgnoreCase) >= 0));

String small replacement [duplicate]

This question already has answers here:
Fastest way to trim a string and convert it to lower case
(6 answers)
Closed 6 years ago.
I am searching for a simple way to remove underscores from strings and replacing the next character with its upper case letter.
For example:
From: "data" to: "Data"
From: "data_first" to: "DataFirst"
From: "data_first_second" to: "DataFirstSecond"
Who needs more than one line of code?
var output = Regex.Replace(input, "(?:^|_)($|.)", m => m.Groups[1].Value.ToUpper());
This approach is known as a "finite-state machine" that iterates through the string - in that it has a finite set of states ("is the first letter of a word following an underscore" vs "character inside a word"). This represents the minimal instructions needed to perform the task. You can use a Regular Expression for the same effect, but it would generate at least the same number of instructions at runtime. Writing the code out manually guarantees a minimal runtime.
The advantage of this approach is sheer performance: there is no unnecessary allocation of intermediate strings being performed, and it iterates through the input string only once, giving a time complexity of O(n) and a space complexity of O(n). This cannot be improved upon.
public static String ConvertUnderscoreSeparatedStringToPascalCase(String input) {
Boolean isFirstLetter = true;
StringBuilder output = new StringBuilder( input.Length );
foreach(Char c in input) {
if( c == '_' ) {
isFirstLetter = true;
continue;
}
if( isFirstLetter ) {
output.Append( Char.ToUpper( c ) );
isFirstLetter = false;
}
else {
output.Append( c );
}
}
return output.ToString();
}
You can use String.Split and following LINQ query:
IEnumerable<string> newStrings = "data_first_second".Split('_')
.Select(t => new String(t.Select((c, index) => index == 0 ? Char.ToUpper(c) : c).ToArray()));
string result = String.Join("", newStrings);
All other answers valid... for a culture-aware way:
var textInfo = CultureInfo.CurrentCulture.TextInfo;
var modifiedString = textInfo.ToTitleCase(originalString).Replace("_","")
I've made a fiddle: https://dotnetfiddle.net/NAr5PP
I would do something like this:
string test = "data_first_second";
string[] testArray=test.Split('_');
StringBuilder modifiedString = new StringBuilder();
foreach (string t in testArray)
{
modifiedString.Append(t.First().ToString().ToUpper() + t.Substring(1));
}
test=modifiedString.toString();
Use LINQ and Split method like this:
var result = string.Join("",str.Split('_')
.Select(c => c.First().ToString()
.ToUpper() + String.Join("", c.Skip(1))));

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

Converting "9954-4740-4491-4414" to "99:54:47:40:44:91:44:14" using Regular Expressions

If the title isn't clear enough, here's a procedural way of approaching the problem:
[TestMethod]
public void Foo()
{
var start = "9954-4740-4491-4414";
var sb = new StringBuilder();
var j = 0;
for (var i = 0 ; i < start.Length; i++)
{
if ( start[i] != '-')
{
if (j == 2)
{
sb.AppendFormat(":{0}", start[i]);
j = 1;
}
else
{
sb.Append(start[i]);
j++;
}
}
}
var end = sb.ToString();
Assert.AreEqual(end, "99:54:47:40:44:91:44:14");
}
If you're using C# 4 all you need is this:
string result = string.Join(":", Regex.Matches(start, #"\d{2}").Cast<Match>());
For C# 3 you need to provide a string[] to Join:
string[] digitPairs = Regex.Matches(start, #"\d{2}")
.Cast<Match>()
.Select(m => m.Value)
.ToArray();
string result = string.Join(":", digitPairs);
I agree with "why bother with regular expressions?"
string.Join(":", str.Split('-').Select(s => s.Insert(2, ":"));
Regex.Replace version, although I like Mark's answer better:
string res = Regex.Replace(start,
#"(\d{2})(\d{2})-(\d{2})(\d{2})-(\d{2})(\d{2})-(\d{2})(\d{2})",
#"$1:$2:$3:$4:$5:$6:$7:$8");
After a while of experimenting, I've found a way to do it by using a single regular expression that works with input of unlimited length:
Regex.Replace(start, #"(?'group'\d\d)-|(?'group'\d\d)(?!$)", #"$1:")
When using named groups (the (?'name') stuff) with same name, captures are stored in the same group. That way, it is possible to replace distinct matches with same value.
It also makes use of negative lookahead (the (?!) stuff).
You don't need them: strip the '-' characters and then insert a colon between each pair of numbers. Unless I've misunderstood the desired output format.

What's the most efficient way to format the following string?

I have a very simple question, and I shouldn't be hung up on this, but I am. Haha!
I have a string that I receive in the following format(s):
123
123456-D53
123455-4D
234234-4
123415
The desired output, post formatting, is:
123-455-444
123-455-55
123-455-5
or
123-455
The format is ultimately dependent upon the total number of characters in the original string..
I have several ideas of how to do this, but I keep thing there's a better way than string.Replace and concatenate...
Thanks for the suggestions..
Ian
Tanascius is right but I cant comment or upvote due to my lack of rep but if you want additional info on the string.format Ive found this helpful.
http://blog.stevex.net/string-formatting-in-csharp/
I assume this does not merely rely upon the inputs always being numeric? If so, I'm thinking of something like this
private string ApplyCustomFormat(string input)
{
StringBuilder builder = new StringBuilder(input.Replace("-", ""));
int index = 3;
while (index < builder.Length)
{
builder.Insert(index, "-");
index += 4;
}
return builder.ToString();
}
Here's a method that uses a combination of regular expressions and LINQ to extract groups of three letters at a time and then joins them together again. Note: it assumes that the input has already been validated. The validation can also be done with a regular expression.
string s = "123456-D53";
string[] groups = Regex.Matches(s, #"\w{1,3}")
.Cast<Match>()
.Select(match => match.Value)
.ToArray();
string result = string.Join("-", groups);
Result:
123-456-D53
EDIT: See history for old versions.
You could use char.IsDigit() for finding digits, only.
var output = new StringBuilder();
var digitCount = 0;
foreach( var c in input )
{
if( char.IsDigit( c ) )
{
output.Append( c );
digitCount++;
if( digitCount % 3 == 0 )
{
output.Append( "-" );
}
}
}
// Remove possible last -
return output.ToString().TrimEnd('-');
This code should fill from left to right (now I got it, first read, then code) ...
Sorry, I still can't test this right now.
Not the fastest, but easy on the eyes (ed: to read):
string Normalize(string value)
{
if (String.IsNullOrEmpty(value)) return value;
int appended = 0;
var builder = new StringBuilder(value.Length + value.Length/3);
for (int ii = 0; ii < value.Length; ++ii)
{
if (Char.IsLetterOrDigit(value[ii]))
{
builder.Append(value[ii]);
if ((++appended % 3) == 0) builder.Append('-');
}
}
return builder.ToString().TrimEnd('-');
}
Uses a guess to pre-allocate the StringBuilder's length. This will accept any Alphanumeric input with any amount of junk being added by the user, including excess whitespace.

Categories