正则表达式 - 多行问题

3

我感觉自己已经疲惫不堪了,这也许是为什么我看不出明显的错误。无论如何,我想要以下正则表达式:

#BIZ[.\s]*#ENDBIZ

用于匹配 #BIZ 标签、#ENDBIZ 标签以及标签之间的所有文本。例如,如果给定一些文本,我希望该表达式能够匹配:

#BIZ
some text some test
more text
maybe some code
#ENDBIZ

目前,这个正则表达式没有匹配到任何内容。我做错了什么?

更多细节

我正在使用PHP进行以下操作:

preg_replace('/#BIZ[.\s]*#ENDBIZ/', '我的新文本', $strMultiplelines);


1
你使用哪种语言或环境来处理这个正则表达式? - victor hugo
8个回答

13
点在字符类中失去了其特殊含义,也就是说,[.\s]表示“匹配句点或空格”。我认为你想要的是[\s\S],它表示“匹配空白或非空白字符”。
preg_replace('/#BIZ[\s\S]*#ENDBIZ/', 'my new text', $strMultiplelines);

编辑:关于点和字符类的一些说明:

默认情况下,点不匹配换行符。大多数(全部?)正则表达式实现都有一种方法可以指定它匹配换行符,但具体实现方式因实现而异。唯一能以兼容的方式匹配(真正的)任何字符的方法是将简写类与其否定配对使用 - [\s\S][\w\W][\d\D]。根据我的个人经验,第一种方式似乎最常见,可能是因为在需要匹配换行符时使用,并包括 \s 可以使其更明确。

此外,点并不是唯一一个在字符类中失去意义的特殊字符。实际上,在字符类中有特殊含义的字符只有 ^-\]。请查看Regular-Expressions.info上的字符类页面中的“字符类内的元字符”部分。.


不,它不会 - 至少在 PCRE 中不会,preg_应该使用它。当我使用它们时,点在正则表达式内外意思是相同的。 - Chris Lutz
@Chris Lutz — 我刚刚测试了一下。使用 PCRE,"[.\s]" 只会匹配到 "foo bar" 中的空格。你可以自己试试看。 - Ben Blank
本说得对:在字符类内,点只匹配一个点。 - Alan Moore
1
该死。我相信你,已经去掉了我的-1,但我无法让它工作。PHP对我来说很自以为是。不管怎样,当PCRE语言的工作方式与Perl不同时,我总是会被扔出去。这就是_Perl_兼容正则表达式不兼容Perl的原因,这毫无意义。 - Chris Lutz
实际上,Perl的工作方式相同。这很奇怪,因为我发誓以前在方括号内成功地使用过点。我今天心情不好,需要停止拖延,开始完成我的期末。 - Chris Lutz
1
小心,上面的解决方案是贪婪的...需要使用 [\s\S]*?(带问号) - nonopolarity

2
// Replaces all of your code with "my new text", but I do not think
// this is actually what you want based on your description.
preg_replace('/#BIZ(.+?)#ENDBIZ/s', 'my new text', $contents);

// Actually "gets" the text, which is what I think you might be looking for.
preg_match('/(#BIZ)(.+?)(#ENDBIZ)/s', $contents, $matches);
list($dummy, $startTag, $data, $endTag) = $matches;

显然你并没有真正尝试过,因为对我来说它完全可以正常工作。匹配换行符不是问题,因为我在表达式中没有使用^或$。 - Beau Simensen
2
这个正则表达式之所以能工作是因为 /s 修饰符允许圆点匹配换行符。 - Alan Moore
我还没有尝试过,因为 PHP 不喜欢我(而我也反感它,但这是另一回事)。我错过了 /s 修饰符。否则,就像 Alan M 说的那样。 - Chris Lutz

2

1
错误在于字符组[.\s],它会匹配一个点(而不是任何字符)或空格。你可能尝试使用.来匹配换行符获取.*。可以通过启用单行选项来实现这一点(在.NET正则表达式中,使用(?s:))。
(?s:#BIZ.*?#ENDBIZ)

1

你可以使用

preg_replace('/#BIZ.*?#ENDBIZ/s', 'my new text', $strMultiplelines);

's'修饰符表示“匹配任何字符,包括换行符”。'?'表示不要贪心,例如:

foo

#BIZ
some text some test
more text
maybe some code
#ENDBIZ

bar

#BIZ
some text some test
more text
maybe some code
#ENDBIZ

hello world

非贪婪模式无法去除中间的“bar”。


1

根据你在使用正则表达式的环境不同,可能需要特别注意来正确地解析多行文本,例如在 Python 中使用 re.DOTALL。那么这是什么环境呢?


它需要单行选项(也匹配换行符),而不是多行选项($^锚点也在换行符处)。 - Daniel Brückner
你是对的——DOTALL,而不是MULTILINE!谢谢你的发现——我正在编辑。 - Alex Martelli

0

除非我漏掉了什么,否则你可以使用 Perl 中相同的方式处理,即在末尾使用 /m/s 修饰符?奇怪的是,其他答案 已经正确指出了这一点,却被 投票否决 了?!


我很累,错过了 /s 部分。我已经纠正了负评。 - Chris Lutz

-1

看起来你正在进行 JavaScript 正则表达式,你需要在表达式末尾指定 m 标志以启用多行模式:

var re = /^deal$/mg 

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