Regex 正则表达式改进建议
给定一个字符串 一些文本和[A~标记]以及更多文本和[非标记]和 [另一个~token] 我需要提取“代币”以便以后替换。标记定义为两个标识符,由~分隔,并用[]括起来。我一直在做的是使用Regex 正则表达式改进建议,regex,powershell,Regex,Powershell,给定一个字符串 一些文本和[A~标记]以及更多文本和[非标记]和 [另一个~token] 我需要提取“代币”以便以后替换。标记定义为两个标识符,由~分隔,并用[]括起来。我一直在做的是使用$string-match“\[.*?~..*?\]”,这很有效。而且,据我所知,我正在转义两个括号,对任何字符执行零次或多次,并强制懒惰,然后是~和相同的任何字符序列。因此,我的第一个改进是将*?替换为+?,因为我想要1个或更多,而不是0个或更多。然后我转到$string-match“\[[A-Za-z0-9
$string-match“\[.*?~..*?\]”
,这很有效。而且,据我所知,我正在转义两个括号,对任何字符执行零次或多次,并强制懒惰,然后是~和相同的任何字符序列。因此,我的第一个改进是将*?
替换为+?
,因为我想要1个或更多,而不是0个或更多。然后我转到$string-match“\[[A-Za-z0-9]+~[A-Za-z0-9]+\]”
,这将两个标识符限制为字母数字,这是一个很大的改进。
因此,第一个问题是:
这最后一个解决方案是最好的方法,还是需要进一步改进
另外,目前我只返回一个令牌,因此我在字符串中循环,在找到令牌时替换它们,并循环直到没有令牌为止。但是,我的理解是,默认情况下RegEx是贪婪的,因此我希望最后一个版本返回两个令牌,并且我可以在字典中循环,而不是使用While循环。
所以,第二个问题是:
我只赢了一场比赛,我做错了什么?还是我误解了贪婪匹配的工作原理
编辑:
为了澄清这一点,我使用了$matches,如下所示,但仍然只得到了1的计数
if ($string -match "\[[A-Za-z0-9]+~[A-Za-z0-9]+\]") {
Write-Host "new2: $($matches.count)"
foreach ($key in $matches.keys) {
Write-Host "$($matches.$key)"
}
}
另外,在识别令牌时,我不能真正使用直接替换,因为有大量的潜在替换。我取代币,去掉方括号,然后在~上拆分,得到前缀和后缀值,然后确定一个特定的替换值,我可以用专用的-replace来完成。
最后一点澄清,令牌的数量是可变的。可能只有一个,可能是三个或四个。因此,我的解决方案必须非常灵活。您可以使用
\w
匹配单词字符(字母、数字、下划线)。
这将导致模式\[\w+~\w+\]
现在,您可以使用该模式创建正则表达式对象:
$rgx = [Regex]::new($pattern)
并用replace
操作符替换该模式的所有出现:
$rgx.Replace($inputstring, $replacement)
也许还值得注意的是,正则表达式有一个
.Match
操作符,返回模式的第一次出现,还有一个.Matches
操作符,返回模式的所有出现。以您的示例行为例
$String = "Some text and [A~Token] and more text and [not a token] and [another~token]"
此正则表达式包含捕获组
$RegEx = [RegEx]"\[(\w+~\w+)\][^\[]+\[[^\]]+\][^\[]+\[(\w+~\w+)\]"
if ($string -match $RegEX){
"First token={0} Second token={1}" -f $matches[1],$matches[2]
}
返回:
First token=A~Token Second token=another~token
第一个令牌=一个~token第二个令牌=另一个~token
请参阅上面的RegEx解释
两个标记之间的区域交替与否定类匹配
对于
[
/]
和文本字符[
/]
列出所有标记并使用值,您可以使用如下代码:
$matces = Select-String '\[([\w]+)~([\w]+)\]' -input $string -AllMatches | Foreach {$_.matches}
foreach($value in $matces){
$fullToken = $value.Value;
$firstPart = $value.Groups[1].Value;
$secondPart = $value.Groups[2].Value;
echo "full token found: '$fullToken' first part: '$firstPart' second part: '$secondPart'";
}
注意:在使用()
分组的regex部分中,这允许访问令牌的部分
在此循环中,您可以使用firstPart
和secondPart
找到要插入的适当值,而不是fullToken
至于
\[.*.~.*.\]
不能正常工作,因为它试图与文本[不是令牌]和[other~令牌]
匹配并成功,就像在这个正则表达式中一样,令牌部分允许字符][
。\[^\]\[]*?~[^\]\[]*?
(^
对表达式求反,使其读取:除]之外的所有字符[
)也可以,但如果\w
足够好的话,它不是所有大括号都可读的,你应该告诉我们。在你定义令牌模式要求之前,我们无法帮助你。很有趣。这是一种非常不同的正则表达式和分组方法。我需要深入研究一下,才能完全理解它,但这是一个进步。谢谢。我有一个问题还有一个问题要补充。这里有什么在PS2.0中不起作用的吗?我只支持旧的(古代的)不幸的是,PowerShell。@Gordon实际上我不知道这段代码是否对2.0有效,但如果您有环境,它将很容易尝试执行。没有保证,但从PowerShell-Version 2开始它就可以工作了。@Lotpings,谢谢验证。我挖出了我的2.0测试虚拟机并进行了验证。今晚有一些重构要做。