I am learning validation expressions and have attempted to write one to check a decimal like the example below but I am having some issues.
The number to validate is like this:
00.00 (any 2 numbers, then a ., then any 2 numbers)
This is what I have:
^[0-9]{2}[.][0-9]{2}$
This expression returns false but from a tutorial I read I was under the understanding that it should be written like this:
^ = starting character
[0-9] = any number 0-9
{2} = 2 numbers 0-9
[.] = full stop
$ = end
Use the right tool for the job. If you're parsing decimals, use decimal.TryParse instead of Regex.
string input = "00.00";
decimal d;
var parsed = Decimal.TryParse(input, out d);
If the requirement is to always have a 2 digits then a decimal point then 2 digits you could do:
var lessThan100 = d < 100m;
var twoDecimals = d % 0.01m == 0;
var allOkay = parsed && lessThan100 && twoDecimals;
So our results are
Stage | input = "" | "abc" | "00.00" | "123" | "0.1234"
-------------------------------------------------------------
parsed | false | false | true | true | true
lessThan100 | - | - | true | false | true
twoDecimals | - | - | true | - | false
Although if you really need it to be that exact format then you could do
var separator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
var allOkay = isOkay && input.Length == 5 && input[2] == separator;
If you absolutely have to use Regex then the following works as required:
Regex.IsMatch("12.34", #"^([0-9]{2}\.[0-9]{2})$")
Regex explanation:
^ - start of string
() - match what's inside of brackets
[0-9]{2} exactly 2 characters in the range 0 - 9
\. - full stop (escaped)
$ - end of string
Related
I have a cellphone field that is being validated as such-
[Required(ErrorMessage = "Cell phone is required"),
RegularExpression(Constants.PhoneRegex, ErrorMessage = "Invalid phone number")]
public string CellPhone { get; set; }
This is currently being validated for US phone numbers with this regex,
PhoneRegex = #"^(?!0+$)(\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4}))$";
which I found from https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s02.html
Now there is a new requirement to not allow user to enter all zeros. So I tried ^(?!0+$)(\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4}))$ which I found from another thread RegEx for phone number, all zeros not allowed
This one works when I test it on https://rubular.com/ but in my code it does not work
Example:-
Cellphone | Actual | Expected
------------------------------------
4561237890 | //true | true
1234 | //false | false
0000000000 | //true | false
You can use
^(?!(?:\D*0)+\D*$)\(?([0-9]{3})\)?[-. ]?[0-9]{3}[-. ]?[0-9]{4}$
Here,
^ - start of string
(?!(?:\D*0)+\D*$) - no only one or more 0 digits in the string
\(? - an optional ( char
[0-9]{3} - three digits
\)? - an optional ) char
[-. ]? - an optional space, - or . char
[0-9]{3} - three digits
[-. ]? - an optional space, - or . char
[0-9]{4} - four digits
$ - end of string.
Try this
var regEx = #"^(?<Number>[0-9]{3}[-.\s][0-9]{3}[-.\s][0-9]{4})(?<AllZero>[0]{0,9})$";
var match = Regex.Match(MYSTRING_TO_TEST, regEx, RegexOptions.IgnoreCase);
string validateNumber = match.Groups["Number"].Value;
string allZeroNumber = match.Groups["AllZero"].Value;
If allZeroNumber match is all 0 digit.
I'm currently making a Game and I have already split the string everything right but how I can trim the string and output the last line or a line in the middle?
Code:
text = "Username:King100 ID:100 Level:10";
string[] splittext = text.Split(' ');
foreach (var texs in splittext)
{
Console.WriteLine(texs);
}
Output:
Username:King100
ID:100
Level:10
I just want display the level 10 in the Console how thats works?
thanxs for helping.
Edit: the level can be changed often like 10 or 100 or 1000
Regex is more flexible solution. But if your text format is contsant, you can use this simple way:
string level = text.Substring(text.LastIndexOf(':') + 1);
You can also use a Regular Expression to solve this:
var regex = new Regex(#"Level:(?<Level>\d*)");
var matches = regex.Matches("Username:King100 ID:100 Level:10");
if (matches.Count > 0 && matches[0].Success)
{
Console.WriteLine(matches[0].Groups["Level"].Value);
}
var text = "Username:King100 ID:100 Level:10";
/*
Splits the given string on spaces and then splits on ":"
and creates a Dictionary ("Dictionary<TKey, TValue>")
*/
var dict = text.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
.Select(part => part.Split(':'))
.ToDictionary(split => split[0], split => split[1]);
//If the dictionary count is greater than Zero
if(dict.Count > 0)
{
var levelValue = dict["Level"].ToString();
}
OK, because i'm annoying and totally bored of work, i decided to benchmark everyone's solutions.
The premise was simply to make an array of 1000 (scale) lines of strings (in the given format) with random positive int on the end;
Note : I made every solution int.Parse the result, as it seemed more useful
Mine
This just uses fixed, unsafe, pointers and no error checking
var level = 0;
fixed (char* pitem = item)
{
var len = pitem + item.Length;
for (var p = pitem ; p < len; p++)
if (*p >= '0' && *p <= '9')
level = level * 10 + *p - 48;
else
level = 0;
}
Results
Mode : Release
Test Framework : .NET Framework 4.7.1
Benchmarks runs : 1000 times (averaged)
Scale : 1,000
Name | Average | Fastest | StDv | Cycles | Pass | Gain
--------------------------------------------------------------------------
Mine | 0.095 ms | 0.085 ms | 0.01 | 317,205 | Yes | 96.59 %
Sanan | 0.202 ms | 0.184 ms | 0.02 | 680,747 | Yes | 92.75 %
Zaza | 0.373 ms | 0.316 ms | 0.10 | 1,254,302 | Yes | 86.60 %
Kishore | 0.479 ms | 0.423 ms | 0.06 | 1,620,756 | Yes | 82.81 %
Hussein | 1.045 ms | 0.946 ms | 0.11 | 3,547,305 | Yes | 62.50 %
Maccettura | 2.787 ms | 2.476 ms | 0.39 | 9,474,133 | Base | 0.00 %
Hardkoded | 6.691 ms | 5.927 ms | 0.67 | 22,750,311 | Yes | -140.09 %
Tom | 11.561 ms | 10.635 ms | 0.78 | 39,344,419 | Yes | -314.80 %
Summary
All the solutions do different things in different ways, comparing them is not really apples to apples.
Don't use mine, its totally unrealistic and only for fun. Use the version that makes the most sense to you, that is the most robust and easiest to maintain.
As always, regex is the slowest.
If level is always the last part of the string, and all you care about is the actual number, then you can just do:
var level = text.Split(':').LastOrDefault();
This would just split on ':' and give you the last (or default) element. Given your example input, level = "10".
Try this:
string input = "Username:King100 ID:100 Level:10";
Match m = Regex.Match(input, #"\s*Level:(?<level>\d+)");
if (m.Success&& m.Groups["level"].Success)
Console.WriteLine(m.Groups["level"].Value);
Also works for:
string input = "Username:King100 Level:10 ID:100";
string text = texs.Substring(texs.IndexOf("Level:")+6);
System.Console.WriteLine(text);
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I am new to Regex and i want to extract a specific value from a string, i have strings like:
"20098: Blue Quest"
"95: Internal Comp"
"33: ICE"
and so on.Every string has the same pattern : Number followed by ":" followed by a space and random text. I want to get the numbers at the start for ex: "20098","95","33" etc.
i tried
Regex ex = new regex(#"[0-9]+\: [a-zA-Z]$")
This is not giving me any solution, Where am i going wrong?
(i am using c#)
This is a totally silly solution. However, i decided to benchmark an unchecked pointer version, against the other regex and int parse solutions here in the answers.
You mentioned the strings are always the same format, so i decided to see how fast we could get it.
Yehaa
public unsafe static int? FindInt(string val)
{
var result = 0;
fixed (char* p = val)
{
for (var i = 0; i < val.Length; i++)
{
if (*p == ':')return result;
result = result * 10 + *p - 48;
}
return null;
}
}
I run each test 50 times with 100,000 comparisons, and 1,000,000 respectively with both Lee Gunn's int.parse,The fourth bird version ^\d+(?=: [A-Z]) also my pointer version and ^\d+
Results
Test Framework : .NET Framework 4.7.1
Scale : 100000
Name | Time | Delta | Deviation | Cycles
----------------------------------------------------------------------------
Pointers | 2.597 ms | 0.144 ms | 0.19 | 8,836,015
Int.Parse | 17.111 ms | 1.009 ms | 2.91 | 57,167,918
Regex ^\d+ | 85.564 ms | 10.957 ms | 6.14 | 290,724,120
Regex ^\d+(?=: [A-Z]) | 98.912 ms | 1.508 ms | 7.16 | 336,716,453
Scale : 1000000
Name | Time | Delta | Deviation | Cycles
-------------------------------------------------------------------------------
Pointers | 25.968 ms | 1.150 ms | 1.15 | 88,395,856
Int.Parse | 143.382 ms | 2.536 ms | 2.62 | 487,929,382
Regex ^\d+ | 847.109 ms | 14.375 ms | 21.92 | 2,880,964,856
Regex ^\d+(?=: [A-Z]) | 950.591 ms | 6.281 ms | 20.38 | 3,235,489,411
Not surprisingly regex sucks
If they are all separate strings - you don't need to use a regex, you can simply use:
var s = "20098: Blue Quest";
var index = s.IndexOf(':');
if(index > 0){
if(int.TryParse(s.Substring(0, index), out var number))
{
// Do stuff
}
}
If they're all contained in one sting, you can loop over each line and perform the Substring. Perhaps a bit easier to read as a lot of people aren't comfortable with regular expressions.
In your regex "[0-9]+: [a-zA-Z]$ you match one or more digits followed by a colon and then a single lower or uppercase character.
That would match 20098: B and would not match the digits only.
There are better alternatives besides using a regex like as suggested, but you might match from the beginning of the string ^ one or more digits \d+ and use a positive lookahead (?= to assert that what follows is a colon, whitespace and an uppercase character [A-Z])
^\d+(?=: [A-Z])
Firstly, after colon, yoiu should use \s instead of literal space. Also, if the text after colon can include spaces, the second group should also allow /s and have a + after it.
[0-9]+\:\s[a-zA-Z\s]+$
Secondly, that entire regex will return the entire string. If you only want the first number, then the regex would be simply:
[0-9]+
You can use look-behind ?<= to find any number following ^" (where ^ is the beginning of line):
(?<=^")[0-9]+
The below snippet takes a string as input. What I am trying is to get middle 2 elements of the string if the length is even.
string input = "confir";
string op = "";
op = input.Substring((input.Length - 1) / 2,input.Length/2 -1);//logic
Console.WriteLine(op);//display the output
Output for above snippet is nf.
When input is changed to confirme, output should be fi and not fir
How do I generalize? What is the error in the logic?
Second argument of String.Substring is a length of substring, not index like in Java. So if you need to get substring of two characters, pass 2:
string input = "confirme";
string op = input.Substring((input.Length - 1) / 2, 2);
BTW you should handle case when string is less than 2 characters long:
string op = input.Substring((input.Length - 1) / 2, Math.Min(input.Length, 2));
Tests:
input | op |
---------------------
"" | "" |
"c" | "c" |
"co" | "co" |
"con" | "on" |
"conf" | "on" |
"confir" | "nf" |
"confirme" | "fi" |
string input = "confir";
if(input.Length % 2 == 0)
Console.WriteLine(input.Substring((input.Length / 2)-1, 2));
That should give you the expected result.First check whether the string length is even then instead of (input.Length - 1) / 2, divide length by 2 and subtract 1,then take two characters like this: (input.Length / 2) - 1
Problem : you are providing total length of the string as second argument to the Substring() method.
Solution : Substring() method takes total number of characters tobe removed starting from first argument .
From MSDN : Substring(Int32, Int32)
Retrieves a substring from this instance. The substring starts at a
specified character position and has a specified length.
Replace This:
op = input.Substring((input.Length - 1) / 2,input.Length/2 -1);//logic
With This:
op = input.Substring((input.Length - 1) / 2,2);//logic
Suggestion : you need to check for Empty String and for Even number of charatcters in String.
Complete Code:
string input = "confirme";
string op = "";
if (input.Length > 0 && input.Length % 2 == 0)
{
op = input.Substring((input.Length - 1) / 2, 2);//logic
Console.WriteLine(op);//display the output
}
Using Regex.Replace(mystring, #"[^MV:0-9]", "") will remove any Letters that are not M,V,:, or 0-9 (\d could also be used) the problem is I want to remove anything that is not MV: then numbers.
I need to replace anything that is not this pattern with nothing:
Starting String | Wanted Result
---------------------------------------------------------
sdhfuiosdhusdhMV:1234567890sdfahuosdho | MV:1234567890
MV:2138911230989hdsafh89ash32893h8u098 | MV:2138911230989
809308ej0efj0934jf0934jf4fj84j8904jf09 | Null
123MV:1234321234mnnnio234324234njiojh3 | MV:1234321234
mdfmsdfuiovvvajio123oij213432ofjoi32mm | Null
But what I get with what I have is:
Starting String | Returned Result
---------------------------------------------------------
sdhfuiosdhusdhMV:1234567890sdfahuosdho | MV:1234567890
MV:2138911230989hdsafh89ash32893h8u098 | MV:213891123098989328938098
809308ej0efj0934jf0934jf4fj84j8904jf09 | 809308009340934484890409
123MV:1234321234mnnnio234324234njiojh3 | 123MV:12343212342343242343
mdfmsdfuiovvvajio123oij213432ofjoi32mm | mmvvv1232134232mm
And even if there is a Regex pattern for this would I be better off using something along the lines of:
if (Regex.IsMatch(strMyString, #"MV:"))
{
string[] strarMyString = Regex.Split(strMyString, #"MV:");
string[] strarNumbersAfterMV = Regex.Split(strarMyString[1], #"[^\d]");
string WhatIWant = strarNumbersAfterMV[0]
}
If I went with the Latter option would there be away to have:
string[] strarNumbersAfterMV = Regex.Split(strarMyString[1], #"[^\d]");
Only make one split at the first change from numbers? (It will always start with number following the MV:)
Can't you just do:
string matchedText = null;
var match = Regex.Match(myString, #"MV:[0-9]+");
if (match.Success)
{
matchedText = Value;
}
Console.WriteLine((matchedText == null) ? "Not found" : matchedText);
That should give you exactly what you need.