REGEX: What the meaning of . followed by +? - c#

Sorry to ask this question, but I'm really stuck. This code belongs to someone who already left the company. And it causing problem.
protected override string CleanDataLine(string line)
{
//the regular expression for GlobalSight log
Regex regex = new Regex("\".+\"");
Match match = regex.Match(line);
if (match.Success)
{
string matchPart = match.Value;
matchPart =
matchPart.Replace(string.Format("\"{0}\"",
Delimiter), string.Format("\"{0}\"", "*+*+"));
matchPart = matchPart.Replace(Delimiter, '_');
matchPart =
matchPart.Replace(string.Format("\"{0}\"", "*+*+"),
string.Format("\"{0}\"", Delimiter));
line = line.Replace(match.Value, matchPart);
}
return line;
}
I've spent to much time researching. What was he trying to accomplish?
Thanks for helping.

That regex matches
a quote ("),
followed by one or more (+) characters (any character except newlines (.), as many as possible),
followed by a quote ".
It's not a very good regex. For example, in the string foo "bar" baz "bam" boom, it will match "bar" baz "bam".
If the intention is to match a quoted string, a more appropriate regex would be "[^"]*".

. is any character except \n, + means 1 or more.
So: .+ is "1 or more characters"

The dot matches any character except line breaks.
+ is "one or more" (equal to {1,})

protected override string CleanDataLine(string line)
{
//the regular expression for GlobalSight log
Regex regex = new Regex("\".+\"");
Match match = regex.Match(line);
if (match.Success)
{
string matchPart = match.Value;
matchPart =
matchPart.Replace(string.Format("\"{0}\"",
Delimiter), string.Format("\"{0}\"", "*+*+"));
matchPart = matchPart.Replace(Delimiter, '_');
matchPart =
matchPart.Replace(string.Format("\"{0}\"", "*+*+"),
string.Format("\"{0}\"", Delimiter));
line = line.Replace(match.Value, matchPart);
}
return line;
}
line is just some text, could be Hello World, or anything really.
new Regex("\".+\"") the \" is an escaped quote, this means it's actually looking for a string to start with a double quote. .+ means to find any character not including the new-line character one or more times.
If it does match, then he tries to figure out the part that matched by grabbing the value.
It then just becomes a normal search and replace for whatever string was matched.

Related

Matching optional slash in regex

I need a regex that matches first two words between three "/" characters in url: eg. in /en/help/test/abc/def it should match /en/help/.
I use this regex: /.*?/(.*?)/ however sometimes I have the url without the last slash like /en/help which does not match because of the missing last slash.
Can you help me to adjust the regex to match only "/en/help" part? Thanks
A simple way to solve it is to replace reluctant (.*?)/ with greedy ([^/]*):
/.*?/([^/]*)
This would stop at the third slash if there is one, or at the end of the string if the final slash is not there.
Note that you could replace .*? with the same [^/]* expression for consistency:
/[^/]*/([^/]*)
If characters will contain alphanumeric, then you can use the following pattern:
static void Main(string[] args)
{
string s1 = "/en/help/test/abc/def";
string s2 = "/en/help ";
string pattern =
#"(?ix) #Options
/ #This will match first slash
\w+ #This will match [a-z0-9]
/ #This will match second slash
\w+ #Finally, this again will match [a-z0-9] until 3-rd slash (or end)";
foreach(string s in new[] { s1, s2})
{
var match = Regex.Match(s, pattern);
if (match.Success) Console.WriteLine($"Found: '{match.Value}'");
}
}

Detecting "\" (backslash) using Regex

I have a C# Regex like
[\"\'\\/]+
that I want to use to evaluate and return error if certain special characters are found in a string.
My test string is:
\test
I have a call to this method to validate the string:
public static bool validateComments(string input, out string errorString)
{
errorString = null;
bool result;
result = !Regex.IsMatch(input, "[\"\'\\/]+"); // result is true if no match
// return an error if match
if (result == false)
errorString = "Comments cannot contain quotes (double or single) or slashes.";
return result;
}
However, I am unable to match the backslash. I have tried several tools such as regexpal and a VS2012 extension that both seem to match this regex just fine, but the C# code itself won't. I do realize that C# is escaping the string as it is coming in from a Javascript Ajax call, so is there another way to match this string?
It does match /test or 'test or "test, just not \test
The \ is used even by Regex(es). Try "[\"\'\\\\/]+" (so double escape the \)
Note that you could have #"[""'\\/]+" and perhaps it would be more readable :-) (by using the # the only character you have to escape is the ", by the use of a second "")
You don't really need the +, because in the end [...] means "one of", and it's enough for you.
Don't eat what you can't chew... Instead of regexes use
// result is true if no match
result = input.IndexOfAny(new[] { '"', '\'', '\\', '/' }) == -1;
I don't think anyone ever lost the work because he preferred IndexOf instead of a regex :-)
You can solve this by making the string verbatim like this #:
result = !Regex.IsMatch(input, #"[\""\'\\/]+");
Since backslashes are used as escapes inside regex themselves, I find it best to use verbatim strings when working with the regex library:
string input = #"\test";
bool result = !Regex.IsMatch(input, #"[""'\\]+");
// ^^
// You need to double the double-quotes when working with verbatim strings;
// All other characters, including backslashes, remain unchanged.
if (!result) {
Console.WriteLine("Comments cannot contain quotes (double or single) or slashes.");
}
The only issue with that is that you must double your double-quotes (which is ironically what you need to do in your case).
Demo on ideone.
For the trivial case, I am able to use regexhero.net for your test expression using the simple:
\\
to validate
\test
The code generated by RegExHero:
string strRegex = #"\\";
RegexOptions myRegexOptions = RegexOptions.IgnoreCase;
Regex myRegex = new Regex(strRegex, myRegexOptions);
string strTargetString = #"\test";
foreach (Match myMatch in myRegex.Matches(strTargetString))
{
if (myMatch.Success)
{
// Add your code here
}
}

RegEx.Replace to Replace Whole Words and Skip when Part of the Word

I am using regex to replace certain keywords from a string (or Stringbuilder) with the ones that I choose. However, I fail to build a valid regex pattern to replace only whole words.
For example, if I have InputString = "fox foxy" and want to replace "fox" with "dog" it the output would be "dog dogy".
What is the valid RegEx pattern to take only "fox" and leave "foxy"?
public string Replace(string KeywordToReplace, string Replacement) /
{
this.Replacement = Replacement;
this.KeywordToReplace = KeywordToReplace;
Regex RegExHelper = new Regex(KeywordToReplace, RegexOptions.IgnoreCase);
string Output = RegExHelper.Replace(InputString, Replacement);
return Output;
}
Thanks!
Regexes support a special escape sequence that represents a word boundary. Word-characters are everything in [a-zA-Z0-9]. So a word-boundary is between any character that belongs in this group and a character that doesn't. The escape sequence is \b:
\bfox\b
Do not forget to put '#' symbol before your '\bword\b'.
For example:
address = Regex.Replace(address, #"\bNE\b", "Northeast");
# symbol ensures escape character, backslash(\), does not get escaped!
You need to use boundary..
KeywordToReplace="\byourWord\b"

Regexp skip pattern

Problem
I need to replace all asterisk symbols('*') with percent symbol('%'). The asterisk symbols in square brackets should be ignored.
Example
[Test]
public void Replace_all_asterisks_outside_the_square_brackets()
{
var input = "Hel[*o], w*rld!";
var output = Regex.Replace(input, "What_pattern_should_be_there?", "%")
Assert.AreEqual("Hel[*o], w%rld!", output));
}
Try using a look ahead:
\*(?![^\[\]]*\])
Here's a bit stronger solution, which takes care of [] blocks better, and even escaped \[ characters:
string text = #"h*H\[el[*o], w*rl\]d!";
string pattern = #"
\\. # Match an escaped character. (to skip over it)
|
\[ # Match a character class
(?:\\.|[^\]])* # which may also contain escaped characters (to skip over it)
\]
|
(?<Asterisk>\*) # Match `*` and add it to a group.
";
text = Regex.Replace(text, pattern,
match => match.Groups["Asterisk"].Success ? "%" : match.Value,
RegexOptions.IgnorePatternWhitespace);
If you don't care about escaped characters you can simplify it to:
\[ # Skip a character class
[^\]]* # until the first ']'
\]
|
(?<Asterisk>\*)
Which can be written without comments as: #"\[[^\]]*\]|(?<Asterisk>\*)".
To understand why it works we need to understand how Regex.Replace works: for every position in the string it tries to match the regex. If it fails, it moves one character. If it succeeds, it moves over the whole match.
Here, we have dummy matches for the [...] blocks so we may skip over the asterisks we don't want to replace, and match only the lonely ones. That decision is made in a callback function that checks if Asterisk was matched or not.
I couldn't come up with a pure RegEx solution. Therefore I am providing you with a pragmatic solution. I tested it and it works:
[Test]
public void Replace_all_asterisks_outside_the_square_brackets()
{
var input = "H*]e*l[*o], w*rl[*d*o] [o*] [o*o].";
var actual = ReplaceAsterisksNotInSquareBrackets(input);
var expected = "H%]e%l[*o], w%rl[*d*o] [o*] [o*o].";
Assert.AreEqual(expected, actual);
}
private static string ReplaceAsterisksNotInSquareBrackets(string s)
{
Regex rx = new Regex(#"(?<=\[[^\[\]]*)(?<asterisk>\*)(?=[^\[\]]*\])");
var matches = rx.Matches(s);
s = s.Replace('*', '%');
foreach (Match match in matches)
{
s = s.Remove(match.Groups["asterisk"].Index, 1);
s = s.Insert(match.Groups["asterisk"].Index, "*");
}
return s;
}
EDITED
Okay here is my final attempt ;)
Using negative lookbehind (?<!) and negative lookahead (?!).
var output = Regex.Replace(input, #"(?<!\[)\*(?!\])", "%");
This also passes the test in the comment to another answer "Hel*o], w*rld!"

Removing all whitespace lines from a multi-line string efficiently

In C# what's the best way to remove blank lines i.e., lines that contain only whitespace from a string? I'm happy to use a Regex if that's the best solution.
EDIT: I should add I'm using .NET 2.0.
Bounty update: I'll roll this back after the bounty is awarded, but I wanted to clarify a few things.
First, any Perl 5 compat regex will work. This is not limited to .NET developers. The title and tags have been edited to reflect this.
Second, while I gave a quick example in the bounty details, it isn't the only test you must satisfy. Your solution must remove all lines which consist of nothing but whitespace, as well as the last newline. If there is a string which, after running through your regex, ends with "/r/n" or any whitespace characters, it fails.
If you want to remove lines containing any whitespace (tabs, spaces), try:
string fix = Regex.Replace(original, #"^\s*$\n", string.Empty, RegexOptions.Multiline);
Edit (for #Will): The simplest solution to trim trailing newlines would be to use TrimEnd on the resulting string, e.g.:
string fix =
Regex.Replace(original, #"^\s*$\n", string.Empty, RegexOptions.Multiline)
.TrimEnd();
string outputString;
using (StringReader reader = new StringReader(originalString)
using (StringWriter writer = new StringWriter())
{
string line;
while((line = reader.ReadLine()) != null)
{
if (line.Trim().Length > 0)
writer.WriteLine(line);
}
outputString = writer.ToString();
}
off the top of my head...
string fixed = Regex.Replace(input, "\s*(\n)","$1");
turns this:
fdasdf
asdf
[tabs]
[spaces]
asdf
into this:
fdasdf
asdf
asdf
Using LINQ:
var result = string.Join("\r\n",
multilineString.Split(new string[] { "\r\n" }, ...None)
.Where(s => !string.IsNullOrWhitespace(s)));
If you're dealing with large inputs and/or inconsistent line endings you should use a StringReader and do the above old-school with a foreach loop instead.
Alright this answer is in accordance to the clarified requirements specified in the bounty:
I also need to remove any trailing newlines, and my Regex-fu is
failing. My bounty goes to anyone who can give me a regex which passes
this test: StripWhitespace("test\r\n \r\nthis\r\n\r\n") ==
"test\r\nthis"
So Here's the answer:
(?<=\r?\n)(\s*$\r?\n)+|(?<=\r?\n)(\r?\n)+|(\r?\n)+\z
Or in the C# code provided by #Chris Schmich:
string fix = Regex.Replace("test\r\n \r\nthis\r\n\r\n", #"(?<=\r?\n)(\s*$\r?\n)+|(?<=\r?\n)(\r?\n)+|(\r?\n)+\z", string.Empty, RegexOptions.Multiline);
Now let's try to understand it. There are three optional patterns in here which I am willing to replace with string.empty.
(?<=\r?\n)(\s*$\r?\n)+ - matches one to unlimited lines containing only white space and preceeded by a line break (but does not match the first preceeding line breaks).
(?<=\r?\n)(\r?\n)+ - matches one to unlimited empty lines with no content that are preceeded by a line break (but does not match the first preceeding line breaks).
(\r?\n)+\z - matches one to unlimited line breaks at the end of the tested string (trailing line breaks as you called them)
That satisfies your test perfectly! But also satisfies both \r\n and \n line break styles! Test it out! I believe this will be the most correct answer, although simpler expression would pass your specified bounty test, this regex passes more complex conditions.
EDIT: #Will pointed out a potential flaw in the last pattern match of the above regex in that it won't match multiple line breaks containing white space at the end of the test string. So let's change that last pattern to this:
\b\s+\z The \b is a word boundry (beginning or END of a word), the \s+ is one or more white space characters, the \z is the end of the test string (end of "file"). So now it will match any assortment of whitespace at the end of the file including tabs and spaces in addition to carriage returns and line breaks. I tested both of #Will's provided test cases.
So all together now, it should be:
(?<=\r?\n)(\s*$\r?\n)+|(?<=\r?\n)(\r?\n)+|\b\s+\z
EDIT #2: Alright there is one more possible case #Wil found that the last regex doesn't cover. That case is inputs that have line breaks at the beginning of the file before any content. So lets add one more pattern to match the beginning of the file.
\A\s+ - The \A match the beginning of the file, the \s+ match one or more white space characters.
So now we've got:
\A\s+|(?<=\r?\n)(\s*$\r?\n)+|(?<=\r?\n)(\r?\n)+|\b\s+\z
So now we have four patterns for matching:
whitespace at the beginning of the file,
redundant line breaks containing white space, (ex: \r\n \r\n\t\r\n)
redundant line breaks with no content, (ex: \r\n\r\n)
whitespace at the end of the file
not good. I would use this one using JSON.net:
var o = JsonConvert.DeserializeObject(prettyJson);
new minifiedJson = JsonConvert.SerializeObject(o, Formatting.None);
In response to Will's bounty, which expects a solution that takes "test\r\n \r\nthis\r\n\r\n" and outputs "test\r\nthis", I've come up with a solution that makes use of atomic grouping (aka Nonbacktracking Subexpressions on MSDN). I recommend reading those articles for a better understanding of what's happening. Ultimately the atomic group helped match the trailing newline characters that were otherwise left behind.
Use RegexOptions.Multiline with this pattern:
^\s+(?!\B)|\s*(?>[\r\n]+)$
Here is an example with some test cases, including some I gathered from Will's comments on other posts, as well as my own.
string[] inputs =
{
"one\r\n \r\ntwo\r\n\t\r\n \r\n",
"test\r\n \r\nthis\r\n\r\n",
"\r\n\r\ntest!",
"\r\ntest\r\n ! test",
"\r\ntest \r\n ! "
};
string[] outputs =
{
"one\r\ntwo",
"test\r\nthis",
"test!",
"test\r\n ! test",
"test \r\n ! "
};
string pattern = #"^\s+(?!\B)|\s*(?>[\r\n]+)$";
for (int i = 0; i < inputs.Length; i++)
{
string result = Regex.Replace(inputs[i], pattern, "",
RegexOptions.Multiline);
Console.WriteLine(result == outputs[i]);
}
EDIT: To address the issue of the pattern failing to clean up text with a mix of whitespace and newlines, I added \s* to the last alternation portion of the regex. My previous pattern was redundant and I realized \s* would handle both cases.
string corrected =
System.Text.RegularExpressions.Regex.Replace(input, #"\n+", "\n");
I'll go with:
public static string RemoveEmptyLines(string value) {
using (StringReader reader = new StringReader(yourstring)) {
StringBuilder builder = new StringBuilder();
string line;
while ((line = reader.ReadLine()) != null) {
if (line.Trim().Length > 0)
builder.AppendLine(line);
}
return builder.ToString();
}
}
Here's another option: use the StringReader class. Advantages: one pass over the string, creates no intermediate arrays.
public static string RemoveEmptyLines(this string text) {
var builder = new StringBuilder();
using (var reader = new StringReader(text)) {
while (reader.Peek() != -1) {
string line = reader.ReadLine();
if (!string.IsNullOrWhiteSpace(line))
builder.AppendLine(line);
}
}
return builder.ToString();
}
Note: the IsNullOrWhiteSpace method is new in .NET 4.0. If you don't have that, it's trivial to write on your own:
public static bool IsNullOrWhiteSpace(string text) {
return string.IsNullOrEmpty(text) || text.Trim().Length < 1;
}
In response to Will's bounty here is a Perl sub that gives correct response to the test case:
sub StripWhitespace {
my $str = shift;
print "'",$str,"'\n";
$str =~ s/(?:\R+\s+(\R)+)|(?:()\R+)$/$1/g;
print "'",$str,"'\n";
return $str;
}
StripWhitespace("test\r\n \r\nthis\r\n\r\n");
output:
'test
this
'
'test
this'
In order to not use \R, replace it with [\r\n] and inverse the alternative. This one produces the same result:
$str =~ s/(?:(\S)[\r\n]+)|(?:[\r\n]+\s+([\r\n])+)/$1/g;
There're no needs for special configuration neither multi line support. Nevertheless you can add s flag if it's mandatory.
$str =~ s/(?:(\S)[\r\n]+)|(?:[\r\n]+\s+([\r\n])+)/$1/sg;
if its only White spaces why don't you use the C# string method
string yourstring = "A O P V 1.5";
yourstring.Replace(" ", string.empty);
result will be "AOPV1.5"
char[] delimiters = new char[] { '\r', '\n' };
string[] lines = value.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
string result = string.Join(Environment.NewLine, lines)
Here is something simple if working against each individual line...
(^\s+|\s+|^)$
Eh. Well, after all that, I couldn't find one that would hit all the corner cases I could figure out. The following is my latest incantation of a regex that strips
All empty lines from the start of a string
Not including any spaces at the beginning of the first non-whitespace line
All empty lines after the first non-whitespace line and before the last non-whitespace line
Again, preserving all whitespace at the beginning of any non-whitespace line
All empty lines after the last non-whitespace line, including the last newline
(?<=(\r\n)|^)\s*\r\n|\r\n\s*$
which essentially says:
Immediately after
The beginning of the string OR
The end of the last line
Match as much contiguous whitespace as possible that ends in a newline*
OR
Match a newline and as much contiguous whitespace as possible that ends at the end of the string
The first half catches all whitespace at the start of the string until the first non-whitespace line, or all whitespace between non-whitespace lines. The second half snags the remaining whitespace in the string, including the last non-whitespace line's newline.
Thanks to all who tried to help out; your answers helped me think through everything I needed to consider when matching.
*(This regex considers a newline to be \r\n, and so will have to be adjusted depending on the source of the string. No options need to be set in order to run the match.)
String Extension
public static string UnPrettyJson(this string s)
{
try
{
// var jsonObj = Json.Decode(s);
// var sObject = Json.Encode(value); dont work well with array of strings c:['a','b','c']
object jsonObj = JsonConvert.DeserializeObject(s);
return JsonConvert.SerializeObject(jsonObj, Formatting.None);
}
catch (Exception e)
{
throw new Exception(
s + " Is Not a valid JSON ! (please validate it in http://www.jsoneditoronline.org )", e);
}
}
Im not sure is it efficient but =)
List<string> strList = myString.Split(new string[] { "\n" }, StringSplitOptions.None).ToList<string>();
myString = string.Join("\n", strList.Where(s => !string.IsNullOrWhiteSpace(s)).Distinct().ToList());
Try this.
string s = "Test1" + Environment.NewLine + Environment.NewLine + "Test 2";
Console.WriteLine(s);
string result = s.Replace(Environment.NewLine, String.Empty);
Console.WriteLine(result);
s = Regex.Replace(s, #"^[^\n\S]*\n", "");
[^\n\S] matches any character that's not a linefeed or a non-whitespace character--so, any whitespace character except \n. But most likely the only characters you have to worry about are space, tab and carriage return, so this should work too:
s = Regex.Replace(s, #"^[ \t\r]*\n", "");
And if you want it to catch the last line, without a final linefeed:
s = Regex.Replace(s, #"^[ \t\r]*\n?", "");

Categories

Resources