我很难处理看似简单的 Regex 任务。我想将文本中具有大写字符的所有 href 链接替换为具有以下排除项的小写字符。
例如
href="/image-ZOOM.aspx?UPPERcasE=someThing"匹配并替换为
href="/image-zoom.aspx?uppercase=something"
href="/image-coorect.aspx" - 不匹配
它还会排除 href="javascript:function();"并且不会小写 <% %> 之间的任何内容标签。
例如:
href="/images/PDFs/<%=Product.ShortSku %>.pdf"被翻译成
href="/images/**pdfs**/<%=Product.ShortSku %>.pdf"
我试过类似 href="([^"]*[A-Z]+[^"]*)" 的东西但这仍然匹配所有小写字母的链接。你能发光吗?
谢谢!
请您参考如下方法:
棘手的部分是你的 <% ... %>要求。一旦您将 URL 的每个部分分成组,它实际上就非常简单。
href="/images/PDFs/<%=Product.ShortSku %>.pdf"
|_____1_____||__________2_________||_3_|
- 这个组必须存在。
- 这个组是可选的。
- 如果第 2 组不存在,则第 3 组也不存在,在这种情况下,第 1 组匹配整个 href 内容。如果第 2 组存在,则第 3 组将是 href 内容的其余部分。
通过理解上面的内容,你最终得到了其他字符串:
href="/image-ZOOM.aspx?UPPERcasE=someThing"
|________________1_________________|
我最终得到了这个使用命名组的模式:
@"href=""(?!javascript:)(?=[^""]*[A-Z])(?<Start>[^""<]+)(?<Special><%[^""]+%>)?(?<End>[^""]*)"""
-
href="": 匹配 href 和左双引号。 -
(?!javascript:): 否定前瞻以忽略 javascript 函数。 -
(?=[^""]*[A-Z]): 积极向前看,在即将到来的内容中找到大写字母。[^""]*匹配任何不是双引号的字符。这样做是为了避免越过内容末尾并贪婪地匹配不需要的内容。 -
(?<Start>[^""<]+): 匹配任何字符的命名组,只要它不是双引号或左尖括号。查看前面的描述 - 尖括号检查确保我们在<% ... %>时停止遇到内容。如果没有,该模式将继续,直到遇到结束双引号。 -
(?<Special><%[^""]+%>)?: optional 要捕获的命名组<% ... %>内容。尾随?将整个组标记为可选。 -
(?<End>[^""]*): 命名组以匹配任何剩余内容。注意这里我使用*使其匹配零个或多个内容。在 Special 组不存在的情况下,这允许模式的这一部分充当可选匹配项。 -
"": 结束双引号。
示例代码:
string[] inputs =
{
"href=\"/image-ZOOM.aspx?UPPERcasE=someThing\"", // match
"href=\"/image-coorect.aspx\"", // no match, lowercase
"href=\"javascript:function();\"", // no match, javascript
"href=\"/images/PDFs/<%=Product.ShortSku %>.pDf\"", // bypass <% %> content
};
string pattern = @"href=""(?!javascript:)(?=[^""]*[A-Z])(?<Start>[^""<]+)(?<Special><%[^""]+%>)?(?<End>[^""]*)""";
foreach (var input in inputs)
{
Console.WriteLine("{0,6}: {1}", Regex.IsMatch(input, pattern), input);
string result = Regex.Replace(input, pattern,
m => "href=\""
+ m.Groups["Start"].Value.ToLower()
+ m.Groups["Special"].Value
+ m.Groups["End"].Value.ToLower()
+ "\"");
Console.WriteLine("Result: " + result);
Console.WriteLine();
}
这使用 lambda 代替 MatchEvaluator .本质上,我们正在重建字符串并引用命名组,改变我们要修改的组的大小写。这段代码的微妙之处在于,如果一个组不匹配,我们仍然可以引用它,它只会给我们一个空字符串。此外,这在代码中可能并不明显,但是当匹配失败时,Regex.Replace 会原封不动地返回原始字符串。 .
