"(51) 3555-4444" "355544-6ren">
gpt4 book ai didi

C# Regex 用字符串末尾的多个捕获和匹配替换奇怪的行为?

转载 作者:太空宇宙 更新时间:2023-11-03 14:27:45 25 4
gpt4 key购买 nike

我想写一些格式化巴西电话号码的东西,但我希望它从字符串的末尾开始匹配,而不是开头,所以它会根据以下模式转换输入字符串:

"5135554444" -> "(51) 3555-4444"
"35554444" -> "3555-4444"
"5554444" -> "555-4444"

由于开头部分通常会发生变化,所以我考虑使用 $ 符号构建匹配,以便它从末尾开始,然后向后捕获(我是这么想的),将 then 替换为所需的结尾格式,然后,如果它们是空的,就去掉前面的括号“()”。

这是 C# 代码:

s = "5135554444";
string str = Regex.Replace(s, @"\D", ""); //Get rid of non digits, if any
str = Regex.Replace(str, @"(\d{0,2})(\d{0,4})(\d{1,4})$", "($1) $2-$3");
return Regex.Replace(str, @"^\(\) ", ""); //Get rid of empty () at the beginning

对于 10 位数字,返回值符合预期。但除此之外,它最终会表现出一些奇怪的行为。这些是我的结果:

"5135554444" -> "(51) 3555-4444"
"35554444" -> "(35) 5544-44"
"5554444" -> "(55) 5444-4"

它似乎忽略了末尾的 $ 来进行匹配,除非我用少于 7 位的数字进行测试,它会像这样:

"554444" -> "(55) 444-4"
"54444" -> "(54) 44-4"
"4444" -> "(44) 4-4"

请注意,它保持第三个捕获组的“最小”{n} 次始终从末尾捕获它,但是,前两组从头开始捕获,就好像最后一组是非贪婪的最后,只得到最低限度...奇怪还是我?

现在,如果我更改模式,那么在第三次捕获时我使用 {4} 而不是 {1,4} 结果如下:

str = Regex.Replace(str, @"(\d{0,2})(\d{0,4})(\d{4})$", "($1) $2-$3");

"5135554444" -> "(51) 3555-4444" //As expected
"35554444" -> "(35) 55-4444" //The last four are as expected, but "35" as $1?
"54444" -> "(5) -4444" //Again "4444" in $3, why nothing in $2 and "5" in $1?

我知道这可能是我的一些愚蠢,但如果我想在字符串的末尾捕获,那么所有之前的捕获组都将以相反的顺序被捕获,这不是更合理吗?

我认为在最后一个例子中“54444”会变成“5-4444”……然后它不会……

如何做到这一点?

(我知道也许有更好的方法可以使用不同的方法来完成同样的事情......但我真正好奇的是找出为什么 Regex 的这种特殊行为看起来很奇怪。所以,这个答案问题应该集中在解释为什么最后一次捕获锚定在字符串的末尾,以及为什么其他捕获不是,如本例所示。所以我对实际的电话#格式化问题不是特别感兴趣,但要了解正则表达式语法)...

谢谢...

最佳答案

所以您希望第三部分始终有四位数字,第二部分始终为零到四位数字,第一部分始终为零到两位数,但前提是第二部分包含四位数字?

使用

^(\d{0,2}?)(\d{0,4})(\d{4})$

作为 C# 片段,注释:

resultString = Regex.Replace(subjectString, 
@"^ # anchor the search at the start of the string
(\d{0,2}?) # match as few digits as possible, maximum 2
(\d{0,4}) # match up to four digits, as many as possible
(\d{4}) # match exactly four digits
$ # anchor the search at the end of the string",
"($1) $2-$3", RegexOptions.IgnorePatternWhitespace);

通过将? 添加到量词 (??, *?, +?, {a,b}?) 你让它变懒了,我。 e.告诉它匹配尽可能少的字符,同时仍然允许找到整体匹配项。

如果第一组中没有 ?,当尝试匹配 123456 时会发生什么情况?

首先,\d{0,2} 匹配 12

然后,\d{0,4} 匹配 3456

然后,\d{4} 没有任何要匹配的内容,因此正则表达式引擎会回溯,直到再次可以匹配为止。经过四步,\d{4}可以匹配到3456\d{0,4} 为此贪婪地放弃了它匹配的所有内容。

现在,已找到整体匹配 - 无需尝试更多组合。因此,第一组和第三组将包含部分比赛。

关于C# Regex 用字符串末尾的多个捕获和匹配替换奇怪的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3429047/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com