There are a lot of numbers like 200 20.5 329.2...in a file. Now, I need replace every number A with A*0.8. Is there any simple method to replace original value with another based on original value?
Best Regards,
Try this one:
String s = "This is the number 2.5. And this is 7";
s = Regex.Replace(s, #"[+-]?\d+(\.\d*)?", m => {return (Double.Parse(m.ToString())*0.8).ToString();});
// s contains "This is the number 2. And this is 5.6"
Edit: Added the plus/minus sign as an optional character in front. To avoid catching the 5 in 3-5 as negative, you could use ((?<=\s)[+-])? instead of [+-]
Using lambda and slightly better handling of cases like The value is .5. Next sentence:
var s = "This is the number 2.5. And this is 7, .5, 5. Yes.";
var result = Regex.Replace(s, #"[+-]?(\d*\.)?\d+", m => (double.Parse(m.Value) * 0.8).ToString());
Related
Given a list of numbers that are regex patterns, sort them by the last 4 numbers in that numeric value.
I have a list of regex (phone number) patterns and I am trying to sort them by the last 4 characters. Here's a sample list of phone numbers:
8062
\+13066598273
4083100
408320[0-3]
408320[4-6]
752[234569]
\+13066598305
8059
I would like to re-order these numbers by the last 4 numbers so that I would end up with a list like this:
4083100
408320[0-3]
408320[4-6]
752[234569]
8059
8062
\+13066598273
\+13066598305
Now if my patterns were nothing but numbers, I could sort them easily in either SQL or my MVC C# project. In SQL, I could use ORDER BY RIGHT(pattern, 4), or in C# MVC, I could sort my IQueryable list with patterns = patterns.OrderByDescending(s => s.Substring(...etc...)).
Patterns are a bit more difficult. The brackets count as characters, so sorting by the last 4 characters doesn't work as well.
Are there any built-in utilities in C#, MVC, or SQL that allow me to convert regex patterns to the largest possible match?
Given a regex pattern, return the largest possible matching regex that matches my condition. For example, if I had the pattern 4[12]00[1-3], I'd have 6 possible results: 41001, 41002, 41003, 42001, 42002, 42003. Then I can get the biggest number possible, and use that for ordering in my original regex list.
The regex pattern doesn't contain anything like * or +, special characters that may cause infinite combinations.
There may be a C# library that does exactly what I ask for, sorting regex pattern strings.
EDIT:
I've accepted Diego's answer, but it took me a bit of time to wrap my head around it. For other readers who want to know what it's doing, this is what I think Diego is doing:
Make a range of ints, starting at 9999, all the way back to 0. [9999], [9998], [9997]...[0].
Replace the regex-ish part of the strings with a single character. Example, "500[1-5]" would become "500X", or "20[1-9]00[89]" would become "20X00X", so on, so forth.
Get the length of the "last" 4 characters + regex characters.
var len = lastNChars + pattern.Length - Regex.Replace(pattern, #"\[[^\]]+\]", "X").Length;
So for the pattern 20[1-9]00[89], the above formula translates to "len = 4 + 13 - 6", or 11.
Using the len variable from above, get a substring that represents the "last" 4 numbers of the phone number, even with regex characters. The original string = "20[1-9]00[89]", while the new substring = "[1-9]00[89]" (the 20 is gone now)
Enumerate through and compare array values to the substring regex pattern. [9999] doesn't match regex pattern, [9998] doesn't match...[9997] doesn't match...aha! 9009 matches! The first match I get is going to the biggest possible regex match, which is what I want.
So each regex pattern has been converted to its largest possible matching pattern. Now we can use C#/LINQ/other in-built methods that can sort by those sub-regex matches for us!
Thank god I'm dealing with only numbers. If I were trying to do sort regex patterns that were actually words/had alpha characters, that would be way harder, and that array would be hella bigger (I think).
It is hard to find sample strings that match a regular expression without enumerating them all and testing them. I also don't think you will be able to find a C# library that sorts regexes. However, you can solve this problem, however, for the special case of patterns that do not contain quantifiers (such as [0-9]+ or [3-6]{4}) as follows:
const int lastNChars = 4;
var patterns = new string[]{#"8062", #"\+13066598273", #"4083100",
#"408320[0-3]", #"408320[4-6]", #"752[234569]",
#"\+13066598305", #"8059"};
var range = Enumerable.Range(0, (int) Math.Pow(10, lastNChars))
.Reverse().ToArray();
var sortedPatterns = patterns.OrderBy(pattern=> {
var len = lastNChars + pattern.Length
- Regex.Replace(pattern, #"\[[^\]]+\]", "X").Length;
// Get the biggest number in range that matches this regex:
var biggestNumberMatched = range.FirstOrDefault(x =>
Regex.IsMatch(x.ToString(new String('0', lastNChars)),
pattern.Substring(pattern.Length - len, len))
);
return biggestNumberMatched;
}).ToArray();
After which, sortedPatterns contains the desired output.
Here is one solution, credits to Matt Hamilton from this question:
var pList = new List<string>()
{
"01233[0-3]", "12356[1-3]", "55555[7-9]"
};
var paired =
pList.Select(x =>
new KeyValuePair<int, string>
(Int32.Parse(new String((new String(x.Where(Char.IsDigit).Reverse().ToArray()))
.Substring(0, 4).Reverse().ToArray())), x));
var pairedOrdered = paired.OrderByDescending(x => x.Key);
foreach(var kvp in pairedOrdered)
{
Console.WriteLine("Key: {0} Value: {1}", kvp.Key, kvp.Value);
}
Output:
Key: 5613 Value: 12356[1-3]
Key: 5579 Value: 55555[7-9]
Key: 3303 Value: 01233[0-3]
I am trying to write a regular expression which validates a text box to have only digits with length 5 or 9. I found the below regular expression to get this done
^\d{1,5}([,]\d{5})*$
but it could not fix my requirement correctly, Can any one please help me in modifying or writing a new regular expression which supports below pattern.
09103,09101, valid (ending with comma)
09103,09101 valid (not ending with comma)
12345,1234567 Invalid (should not support if 1st digit is length 5 and 2nd less than 9)
12345,123456789 valid (must support only digit length 5 or 9)
Please try the following:
var lines = new []
{
"09103,09101,",
"09103,09101",
"12345,1234567",
"12345,123456789",
"12345"
};
var re = new Regex(#"^\d{1,5}(,(\d{5}|\d{9}))?,?$");
foreach (var line in lines)
{
Console.WriteLine("{0} = {1}", line, re.IsMatch(line) ? "Valid" : "Invalid");
}
Output
09103,09101, = Valid
09103,09101 = Valid
12345,1234567 = Invalid
12345,123456789 = Valid
12345 = Valid
You can run it here: C# Fiddle
Just make the part which was preceded by comma to optional, so that it would match only 12345 or 12345,
^(?:\d{5}|\d{9})(?:,(?:\d{5}|\d{9}))?,?$
DEMO
Try this, for your exact test cases.
^\d{5},?$|^\d{5},\d{5},?$|^\d{5},\d{9},?$
It uses the | character to separate 'alternative' patterns, read it as "or". I.e.
^\d{5}$ OR ^\d{5},\d{5}$ OR ^\d{5},\d{9}$
I'd like to provide users with a fancy license key textbox, that would insert the dashes.
The key is supposed to be 20 characters long ( 4 groups of 5 characters )
I tried using regex, first:
Regex.Replace( text, ".{5}", "$0-" );
that is a problem as the dash is inserted even when there's no following characters, e.g
AAAAA-, that results in not being able to remove the dash as it's automatically re-inserted.
then I thought about telling the regex there should be a following character
Regex.Replace( text, "(.{5})(.)", "$1-$2" );
but that splits the key into group of 5-6-6...
Any ideas?
Use a negative lookahead to avoid - to be added at the last. It matches each 5 digits of input string from the first but not the last 5 digits.
.{5}(?!$)
Replacement string
$0-
DEMO
string str = "12345678909876543212";
string result = Regex.Replace(str, #".{5}(?!$)", "$0-");
Console.WriteLine(result);
Console.ReadLine();
Output:
12345-67890-98765-43212
IDEONE
.{5}[^$]
Use this.This will not put a - at the end.
Replace by
$0-
See demo.
http://regex101.com/r/vY0rD6/3
A linq style method might be to your liking if you fancy a non-regex way...
This can be ran in LinqPad:
var sourceReg = "abcdeFGHIJ12345klmno";
var splitLength=5;
var regList = Enumerable.Range(0, sourceReg.Length/splitLength).Select(i => sourceReg.Substring(i*splitLength, splitLength));
regList.Dump("Registration List");
var regSeparated = string.Join("-", regList);
regSeparated.Dump("Registration with Separators");
Note: doesn't take into account reg codes that don't divide exactly.
See the method above plus others in a similar question:
Add separator to string at every N characters?
Code
string key = "12345678909876543212";
licenseBox.Text = System.Text.RegularExpressions.Regex.Replace(key, #".{5}(?!$)", "$0-");
"As Mentioned Above" - Should work fine.
And the following might also work for you.
Code
string key = "12345678909876543212";
licenseBox.Text = String.Format("{0}-{1}-{2}-{3}", key.Substring(0, 5), key.Substring(5, 5), key.Substring(10, 5), key.Substring(15, 5));
Output
12345-67890-98765-43212
I got a string like this (my readline):
alfa: 10662 beta: -64 gama: 70679 delta: 1001
I need to use some of this numbers as a parameters but these numbers can have varying length. I can imagine that extracting value alfa I can do with:
str1 = readline.Substring(6, 5);
But how would I get the value of gamma if the values of beta and alpha can vary?
You can use a regex to match all the name:value pairs and use capture groups to extract the names and values:
var readline = "alpha: 10662 beta: -64 gamma: 70679 delta: 1001";
var matches = Regex.Matches(readline, #"(?<parameter>\w*):\s*(?<value>-?\d*)");
var dictionary = new Dictionary<string,int>();
foreach (Match m in matches)
{
dictionary.Add(m.Groups["parameter"].Value,int.Parse(m.Groups["value"].Value));
}
Console.WriteLine(dictionary["gamma"]); // output: 70679
I would go about doing it a different way that using substring. First, split on the separators to produce an array of keys/values with the keys in the even positions and the values in the odd positions. Then you can either iterate through the array by 2s choosing the value associated with key desired or, if they are always in the same order, just choose the correct array element to convert.
Apply input validation as needed to make sure you don't have corrupt inputs.
var parameters = line.Split( new [] { ':', ' ' }, StringSplitOptions.RemoveEmptyEntries );
for (var i = 0; i < parameters.Length; i += 2 )
{
var key = parameters[i];
var value = int.Parse( parameters[i+1] );
// do something with the value based on the key
}
It seems like a good fit for a regular expression:
var regex = new Regex(#"(\w+)\:\s(-?\d+)");
var values = from pair in regex.Matches("alfa: 10662 beta: -64 gama: 70679 delta: 1001").OfType<Match>()
select new { Key = pair.Groups[1].Value, pair.Groups[2].Value };
I wouldn't use SubString for this; it will be more verbose and error prone.
At it's simplest, it looks as though all of your data is separated by whitespace. Is this a fair assumption? Is the order of each variable always the same? If so, then you can simply split on whitespace and grab every other number;
If the data is not always of the same form, then I would use a regular expression instead. You can use something of the form:
/alfa: ([+-]\d+)/
Which will capture the number after "alpha:" and the sign. You will need something a bit fancier for floating point values. Honestly, I very rarely use regular expressions, and when I write a non-trivial regex I always use regex buddy, so I don't want to write a comprehensive one here for you as it will take me too long =)
EDIT: See, Mark's Regex is much better than mine.
I'm working with X12 EDI Files (Specifically 835s for those of you in Health Care), and I have a particular vendor who's using a non-HIPAA compliant version (3090, I think). The problem is that in a particular segment (PLB- again, for those who care) they're sending a code which is no longer supported by the HIPAA Standard. I need to locate the specific code, and update it with a corrected code.
I think a Regex would be best for this, but I'm still very new to Regex, and I'm not sure where to begin. My current methodology is to turn the file into an array of strings, find the array that starts with "PLB", break that into an array of strings, find the code, and change it. As you can guess, that's very verbose code for something which should be (I'd think) fairly simple.
Here's a sample of what I'm looking for:
~PLB|1902841224|20100228|49>KC15X078001104|.08~
And here's what I want to change it to:
~PLB|1902841224|20100228|CS>KC15X078001104|.08~
Any suggestions?
UPDATE: After review, I found I hadn't quite defined my question well enough. The record above is an example, but it is not necessarilly a specific formatting match- there are three things which could change between this record and some other (in another file) I'd have to fix. They are:
The Pipe (|) could potentially be any non-alpha numeric character. The file itself will define which character (normally a Pipe or Asterisk).
The > could also be any other non-alpha numeric character (most often : or >)
The set of numbers immediately following the PLB is an identifier, and could change in format and length. I've only ever seen numeric Ids there, but technically it could be alpha numeric, and it won't necessarilly be 10 characters.
My Plan is to use String.Format() with my Regex match string so that | and > can be replaced with the correct characters.
And for the record. Yes, I hate ANSI X12.
Assuming that the "offending" code is always 49, you can use the following:
resultString = Regex.Replace(subjectString, #"(?<=~PLB|\d{10}|\d{8}|)49(?=>\w+|)", "CS");
This looks for 49 if it's the first element after a | delimiter, preceded by a group of 8 digits, another |, a group of 10 digits, yet another |, and ~PLB. It also looks if it is followed by >, then any number of alphanumeric characters, and one more |.
With the new requirements (and the lucky coincidence that .NET is one of the few regex flavors that allow variable repetition inside lookbehind), you can change that to:
resultString = Regex.Replace(subjectString, #"(?<=~PLB\1\w+\1\d{8}(\W))49(?=\W\w+\1)", "CS");
Now any non-alphanumeric character is allowed as separator instead of | or > (but in the case of | it has to be always the same one), and the restrictions on the number of characters for the first field have been loosened.
Another, similar approach that works on any valid X12 file to replace a single data value with another on a matching segment:
public void ReplaceData(string filePath, string segmentName,
int elementPosition, int componentPosition,
string oldData, string newData)
{
string text = File.ReadAllText(filePath);
Match match = Regex.Match(text,
#"^ISA(?<e>.).{100}(?<c>.)(?<s>.)(\w+.*?\k<s>)*IEA\k<e>\d*\k<e>\d*\k<s>$");
if (!match.Success)
throw new InvalidOperationException("Not an X12 file");
char elementSeparator = match.Groups["e"].Value[0];
char componentSeparator = match.Groups["c"].Value[0];
char segmentTerminator = match.Groups["s"].Value[0];
var segments = text
.Split(segmentTerminator)
.Select(s => s.Split(elementSeparator)
.Select(e => e.Split(componentSeparator)).ToArray())
.ToArray();
foreach (var segment in segments.Where(s => s[0][0] == segmentName &&
s.Count() > elementPosition &&
s[elementPosition].Count() > componentPosition &&
s[elementPosition][componentPosition] == oldData))
{
segment[elementPosition][componentPosition] = newData;
}
File.WriteAllText(filePath,
string.Join(segmentTerminator.ToString(), segments
.Select(e => string.Join(elementSeparator.ToString(),
e.Select(c => string.Join(componentSeparator.ToString(), c))
.ToArray()))
.ToArray()));
}
The regular expression used validates a proper X12 interchange envelope and assures that all segments within the file contain at least a one character name element. It also parses out the element and component separators as well as the segment terminator.
Assuming that your code is always a two digit number that comes after a pipe character | and before the greater than sign > you can do it like this:
var result = Regex.Replace(yourString, #"(\|)(\d{2})(>)", #"$1CS$3");
You can break it down with regex yes.
If i understand your example correctly the 2 characters between the | and the > need to be letters and not digits.
~PLB\|\d{10}\|\d{8}\|(\d{2})>\w{14}\|\.\d{2}~
This pattern will match the old one and capture the characters between the | and the >. Which you can then use to modify (lookup in a db or something) and do a replace with the following pattern:
(?<=|)\d{2}(?=>)
This will look for the ~PLB|#|#| at the start and replace the 2 numbers before the > with CS.
Regex.Replace(testString, #"(?<=~PLB|[0-9]{10}|[0-9]{8})(\|)([0-9]{2})(>)", #"$1CS$3")
The X12 protocol standard allows the specification of element and component separators in the header, so anything that hard-codes the "|" and ">" characters could eventually break. Since the standard mandates that the characters used as separators (and segment terminators, e.g., "~") cannot appear within the data (there is no escape sequence to allow them to be embedded), parsing the syntax is very simple. Maybe you're already doing something similar to this, but for readability...
// The original segment string (without segment terminator):
string segment = "PLB|1902841224|20100228|49>KC15X078001104|.08";
// Parse the segment into elements, then the fourth element
// into components (bounds checking is omitted for brevity):
var elements = segment.Split('|');
var components = elements[3].Split('>');
// If the first component is the bad value, replace it with
// the correct value (again, not checking bounds):
if (components[0] == "49")
components[0] = "CS";
// Reassemble the segment by joining the components into
// the fourth element, then the elements back into the
// segment string:
elements[3] = string.Join(">", components);
segment = string.Join("|", elements);
Obviously more verbose than a single regular expression but parsing X12 files is as easy as splitting strings on a single character. Except for the fixed length header (which defines the delimiters), an entire transaction set can be parsed with Split:
// Starting with a string that contains the entire 835 transaction set:
var segments = transactionSet.Split('~');
var segmentElements = segments.Select(s => s.Split('|')).ToArray();
// segmentElements contains an array of element arrays,
// each composite element can be split further into components as shown earlier
What I found is working is the following:
parts = original.Split(record);
for(int i = parts.Length -1; i >= 0; i--)
{
string s = parts[i];
string nString =String.Empty;
if (s.StartsWith("PLB"))
{
string[] elems = s.Split(elem);
if (elems[3].Contains("49" + subelem.ToString()))
{
string regex = string.Format(#"(\{0})49({1})", elem, subelem);
nString = Regex.Replace(s, regex, #"$1CS$2");
}
I'm still having to split my original file into a set of strings and then evaluate each string, but the that seams to be working now.
If anyone knows how to get around that string.Split up at the top, I'd love to see a sample.