在正则表达式中查找特定单词以及特殊字符
Find specific word in reg ex along with special character
string emailBody = " holla holla testing is for NewFinancial History:\"xyz\" dsd NewFinancial History:\"abc\" NewEBTDI$:\"abc\" dsds ";
emailBody = string.Join(" ", Regex.Split(emailBody.Trim(), @"(?:\r\n|\n|\r)"));
var keys = Regex.Matches(emailBody, @"\bNew\B(.+?):", RegexOptions.Singleline).OfType<Match>().Select(m => m.Groups[0].Value.Replace(":", "")).Distinct().ToArray();
foreach (string key in keys)
{
List<string> valueList = new List<string>();
string regex = "" + key + ":" + "\"(?<" + GetCleanKey(key) + ">[^\"]*)\"";
var matches = Regex.Matches(emailBody, regex, RegexOptions.Singleline);
foreach (Match match in matches)
{
if (match.Success)
{
string value = match.Groups[GetCleanKey(key)].Value;
if (!valueList.Contains(value.Trim()))
{
valueList.Add(value.Trim());
}
}
}
public string GetCleanKey(string key)
{
return key.Replace(" ", "").Replace("-", "").Replace("#", "").Replace("$", "").Replace("*", "").Replace("!", "").Replace("@", "")
.Replace("%", "").Replace("^", "").Replace("&", "").Replace("(", "").Replace(")", "").Replace("[", "").Replace("]", "").Replace("?", "")
.Replace("<", "").Replace(">", "").Replace("'", "").Replace(";", "").Replace("/", "").Replace("\"", "").Replace("+", "").Replace("~", "").Replace("`", "")
.Replace("{", "").Replace("}", "").Replace("+", "").Replace("|", "");
}
在我上面的代码中,我试图获取 NewEBTDI$:
旁边的值,即 "abc"
。
当我在模式中包含 $
签名时,它不会搜索字段名称旁边的值。
如果 $
被删除并且只指定 NewEBTDI
然后它搜索值。
我想搜索带有 $
符号的值。
处理在正则表达式中具有特殊含义但必须按原样搜索的字符的正确方法是转义它们。您可以使用 Regex.Escape
执行此操作。在您的情况下,它是 $
符号,这意味着 行尾 在正则表达式中,如果未转义。
string regex = "" + Regex.Escape(key) + ":" + "\"(?<" + Regex.Escape(GetCleanKey(key))
+ ">[^\"]*)\"";
或
string regex = String.Format("{0}:\"(?<{1}>[^\"]*)\"",
Regex.Escape(key),
Regex.Escape(GetCleanKey(key)));
或使用 VS 2015,使用字符串插值:
string regex = $"{Regex.Escape(key)}:\"(?<{Regex.Escape(GetCleanKey(key))}>[^\"]*)\"";
(它确实比实际看起来更好,因为 C# 编辑器对字符串部分和嵌入的 C# 表达式进行了不同的着色。)
目前还不清楚最终目标是什么,但模式中的 $
是一种模式转义,这意味着要么是行的结尾,要么是缓冲区的结尾,具体取决于 MultiLine
是否设置。
为什么不直接将 :
之前的文本捕获到命名捕获中?然后提取引用的操作值如:
var data = "...is for NewFinancial History:\"xyz\" dsd NewFinancial History:\"abc\" NewEBTDI$:\"abc\" dsds";
var pattern = @"
(?<New>New[^:]+) # Capture all items after `New` that is *not* (`^`) a `:`, one or more.
: # actual `:`
\x22 # actual quote character begin anchor
(?<InQuotes>[^\x22]+) # text that is not a quote, one or more
\x22 # actual quote ending anchor
";
// IgnorePatternWhitespace allows us to comment the pattern. Does not affect processing.
Regex.Matches(data, pattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture)
.OfType<Match>()
.Select(mt => new
{
NewText = mt.Groups["New"].Value,
Text = mt.Groups["InQuotes"].Value
});
结果
注意我使用十六进制转义 \x22
而不是转义模式中的 \"
以便于使用它。因为它避免了 C# 编译器过早地转义需要保持完整的模式转义。
string emailBody = " holla holla testing is for NewFinancial History:\"xyz\" dsd NewFinancial History:\"abc\" NewEBTDI$:\"abc\" dsds ";
emailBody = string.Join(" ", Regex.Split(emailBody.Trim(), @"(?:\r\n|\n|\r)"));
var keys = Regex.Matches(emailBody, @"\bNew\B(.+?):", RegexOptions.Singleline).OfType<Match>().Select(m => m.Groups[0].Value.Replace(":", "")).Distinct().ToArray();
foreach (string key in keys)
{
List<string> valueList = new List<string>();
string regex = "" + key + ":" + "\"(?<" + GetCleanKey(key) + ">[^\"]*)\"";
var matches = Regex.Matches(emailBody, regex, RegexOptions.Singleline);
foreach (Match match in matches)
{
if (match.Success)
{
string value = match.Groups[GetCleanKey(key)].Value;
if (!valueList.Contains(value.Trim()))
{
valueList.Add(value.Trim());
}
}
}
public string GetCleanKey(string key)
{
return key.Replace(" ", "").Replace("-", "").Replace("#", "").Replace("$", "").Replace("*", "").Replace("!", "").Replace("@", "")
.Replace("%", "").Replace("^", "").Replace("&", "").Replace("(", "").Replace(")", "").Replace("[", "").Replace("]", "").Replace("?", "")
.Replace("<", "").Replace(">", "").Replace("'", "").Replace(";", "").Replace("/", "").Replace("\"", "").Replace("+", "").Replace("~", "").Replace("`", "")
.Replace("{", "").Replace("}", "").Replace("+", "").Replace("|", "");
}
在我上面的代码中,我试图获取 NewEBTDI$:
旁边的值,即 "abc"
。
当我在模式中包含 $
签名时,它不会搜索字段名称旁边的值。
如果 $
被删除并且只指定 NewEBTDI
然后它搜索值。
我想搜索带有 $
符号的值。
处理在正则表达式中具有特殊含义但必须按原样搜索的字符的正确方法是转义它们。您可以使用 Regex.Escape
执行此操作。在您的情况下,它是 $
符号,这意味着 行尾 在正则表达式中,如果未转义。
string regex = "" + Regex.Escape(key) + ":" + "\"(?<" + Regex.Escape(GetCleanKey(key))
+ ">[^\"]*)\"";
或
string regex = String.Format("{0}:\"(?<{1}>[^\"]*)\"",
Regex.Escape(key),
Regex.Escape(GetCleanKey(key)));
或使用 VS 2015,使用字符串插值:
string regex = $"{Regex.Escape(key)}:\"(?<{Regex.Escape(GetCleanKey(key))}>[^\"]*)\"";
(它确实比实际看起来更好,因为 C# 编辑器对字符串部分和嵌入的 C# 表达式进行了不同的着色。)
目前还不清楚最终目标是什么,但模式中的 $
是一种模式转义,这意味着要么是行的结尾,要么是缓冲区的结尾,具体取决于 MultiLine
是否设置。
为什么不直接将 :
之前的文本捕获到命名捕获中?然后提取引用的操作值如:
var data = "...is for NewFinancial History:\"xyz\" dsd NewFinancial History:\"abc\" NewEBTDI$:\"abc\" dsds";
var pattern = @"
(?<New>New[^:]+) # Capture all items after `New` that is *not* (`^`) a `:`, one or more.
: # actual `:`
\x22 # actual quote character begin anchor
(?<InQuotes>[^\x22]+) # text that is not a quote, one or more
\x22 # actual quote ending anchor
";
// IgnorePatternWhitespace allows us to comment the pattern. Does not affect processing.
Regex.Matches(data, pattern, RegexOptions.IgnorePatternWhitespace | RegexOptions.ExplicitCapture)
.OfType<Match>()
.Select(mt => new
{
NewText = mt.Groups["New"].Value,
Text = mt.Groups["InQuotes"].Value
});
结果
注意我使用十六进制转义 \x22
而不是转义模式中的 \"
以便于使用它。因为它避免了 C# 编译器过早地转义需要保持完整的模式转义。