DotAll和多行RegEx

4

我希望你能帮我翻译一下关于IT技术的内容。以下是需要翻译的内容:

我在使用Powershell中的正则表达式时遇到了一些麻烦。似乎存在某种实现错误或其他问题。

我想要处理的文本是一个HTML文件,它看起来像这样(示例1):

<span>[Mobile: %mobile% |] Phone: %telephone% [| Fax: %faxNumber%]</span>
<Span>

问题在于,由于HTML编辑器的原因,我可能会得到像这样的内容(示例2):
<span>[Mobile: 

%mobile% |] Phone: %telephone% [| Fax: &nbsp;&nbsp;%faxNumber%]</span>

如您所见,我们得到了换行和HTML转义,修复了空格&nbsp;

我的Powershell正则表达式如下:

$x = $x -ireplace '(?ms)\[(.?){7}Fax(.*?)\]', 'MyReplacement1'

and this

$x = $x -ireplace '(?ms)\[(.?){7}Mobile(.*?)\]', 'MyReplacement2'

基本上,[表示变量的开始,]表示结束。这会带来两个问题:
1. 由于我们有两个变量,手机和传真,我使用(.?){7}允许一些(这里是7个)字符,避免匹配Mobile附近的第一个[Fax附近的最后一个]之间的整个部分(如果我使用(.*?)而不是(.?){7}将发生这种情况)。我不确定是否有其他方法,可以允许在起始[和变量关键字“Fax”之间的任何数量(而不是7个)字符。这对于避免添加像&nbsp;&nbsp;这样的内容时产生错误匹配很有用(只有7个字符不够,而像我说的(.*?)则会失败)。希望我能解释清楚(有点难)-如果不能:请随时提问!
2. Powershell的-replace方法没有提供设置正则表达式选项的方式,因此我必须使用(?ms)设置DotAll和multiline模式。如您所见,我在正则表达式模式中使用它。然而:当添加换行符时,就像您在example2中看到的Mobile:%mobile%之间,_regex_将失败且不会进行替换!
我非常感谢任何帮助,甚至是来自专家的正则表达式建议,以避免我现在没有考虑到的任何进一步问题...
编辑: (示例3):
<span>[Mobile: 

%mobile% |] Phone: %telephone% [| Fax: 
%faxNumber%]</span>

是的,我已经看到了。请看我的回答评论,我们把这里的评论删除吧;) - Martin Ender
1个回答

11

在DotAll模式下的技巧是使用[\s\S]代替.。这个字符类匹配任何字符(因为它匹配空格和非空格字符)。([\w\W][\d\D]也可以,但空格似乎是一种惯例。)

要避免7问题,您可以简单地禁止在实际想要匹配的]之前关闭该符号(这也使DotAll变得不必要)。所以像这样的东西应该对您很有效:

\[([^\]:]*)Fax([^\]]*)\]

它看起来有点丑,但它的意思很简单:

\[        # literal [
(         # capturing group 1
  [^\]:]* # match as many non-:, non-] characters as possible
)         # end of group 1
Fax       # literal Fax
(         # capturing group 2
  [^\]]*  # match as many non-] characters as possible
)         # end of group 2
\]        # literal ]

有关字符类的进一步阅读。

请注意,这些模式中没有一个需要多行模式m(无论是您的还是我的),因为它只是使^$分别匹配行开头和结尾。但是,没有任何模式包含这些元字符。所以修饰符不起作用。

我的控制台输出:

PS> $x = "<span>[Mobile: %mobile% |] Phone: %telephone% [| Fax: &nbsp;&nbsp;%faxNumber%]</span>"
PS> $x -ireplace '\[([^\]:]*)Mobile([^\]]*)\]', 'MyReplacement1'
<span>MyReplacement1 Phone: %telephone% [| Fax: &nbsp;&nbsp;%faxNumber%]</span>
PS> $x -ireplace '\[([^\]:]*)Fax([^\]]*)\]', 'MyReplacement2'
<span>[Mobile: %mobile% |] Phone: %telephone% MyReplacement2</span>

感谢您的出色回答。然而还有一些问题:**non-:匹配是什么?此外,当运行我的两个PowerShell命令的该模式时,移动电话得到了很好的替换,但是[| Fax: %faxNumber%]**没有被替换 :-(。在运行在线Rexex验证器时,您的正则表达式似乎是正确的。 - omni
@masi 我添加了 : 以避免潜在的 some[thing: %Fax%] 匹配。但是,如果在括号之间出现 Fax 对你来说不重要,你可以从字符类中删除冒号。我将再次检查我的答案是否适用于后一种情况。 - Martin Ender
@masi 嗯,对我来说它完美地工作了。(不过,我在第一个字符类中改变了方括号的位置,但是对于你的输入字符串,这不应该有影响;无论如何,请看我的编辑) - Martin Ender
不要将$x赋值为内联字符串,而是像这样导入字符串$mystring = Get-Content -Path .\test.html,其中test.html包含我刚刚添加到我的帖子(Example3)的内容,那么它就无法工作。这似乎是一行中断的问题。 - omni
@masi 这个答案似乎解释了这个问题的原因。Get-Content 不会返回带有换行符的字符串,而是每一行都返回一个字符串,需要将它们拼接在一起,这样 -ireplace 才能作用于整个文件。 - Martin Ender
是的,您说得对先生!就像您链接中提到的那样,使用 [string]::Join("\n", (Get-Content test.txt))` 已经解决了我的问题。 - omni

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接