模式匹配也包括连字符

3
我有一段像这样的Perl代码(模式匹配):
$var = "<AT>this is an at command</AT>";

if ($var =~ /<AT>([\s\w]*)<\/AT>/i)
{
    print "Matched in AT command\n";
    print "$var\n\n";
}

如果标签之间的内容没有连字符,它可以正常工作。但是如果在标签之间插入连字符,就无法正常工作,比如这样:<AT>this is an at-command</AT>

有人能修复此正则表达式,使其即使插入连字符也能匹配吗?

请帮帮我,谢谢。

Senthil

5个回答

8

关于字符类

您的模式包含以下子模式:

[\s\w]*
[...] 是一个字符类。比如 [aeiou] 匹配一个任何小写元音字母。 [^...] 是一个否定的字符类。 [^aeiou] 匹配除了小写元音字母之外的任何字符。 \s 是空白字符类的速记符号;\w 是单词字符类的快捷方式。两者都不包含连字符。 * 是零个或多个重复指定符号。
现在你应该明白为什么这个模式不匹配连字符:它匹配零个或多个字符,这些字符是空格或单词字符之一。如果你想匹配连字符,那么你可以将它包含到字符类中。
[\s\w-]*

如果您想包括句号、问号和感叹号,那么您只需将它们添加进来即可:
[\s\w.!?-]*

关于连字符的特别说明

在字符类中包含连字符时要小心谨慎。它被用作正则表达式元字符,用来定义字符范围。例如:

[a-z]

匹配任何一个字符,该字符在包括 'a''z' 在内的范围内。相比之下,

[az-]

匹配恰好3个字符之一,'a''z''-'。当您将-作为字符类中的最后一个元素时,它会成为一个字面连字符而不是范围定义。您还可以将其放在第一个元素位置,或通过转义(通过在前面加上反斜杠,这也是转义所有其他正则表达式元字符的方法)。

也就是说,以下3种字符类是相同的:

[az-]         [-az]         [a\-z]

相关问题


“[a-\z]” 应该改为 “[a-z]” 吧。 - codaddict

4

您可以在字符类中添加连字符,如下所示:

if ($var =~ /<AT>([\s\w-]*)<\/AT>/i)

另外,由于您的正则表达式中有一个/,您可以使用不同的分隔符,这样可以避免转义/

if ($var =~m{<AT>([\s\w-]*)</AT>}i)

谢谢codaddict...它很好用...(我想我已经正确接受了答案...) - Senthil kumar

2

使用 \S 替代 \w。

if ($var =~ /<AT>([\s\S]*)<\/AT>/i) {

0

你需要在你的类中添加更多字符,例如 [\s\w-]*(就像 codaddict 告诉你的那样)。

此外,你可能应该使用 lookahead 来匹配你命令的结尾(“我只想匹配它后面的结束语句”),例如:

if ($var =~ /<AT>([^<]*)(?=<\/AT>)/i)

[^<] 代表“除了<之外的任何字符(包括连字符)”。

你甚至可以添加一个向后查找:

if ($var =~ (?<=/<AT>)([^<]*)(?=<\/AT>)/i)

如果你需要更复杂的东西(因为你似乎想要一个小解析器),你应该研究一下语法理论和词法分析器/语法分析器。


0
如果你想要在

之间获取所有内容,你可以使用:
if ($var =~ /<AT>((?:(?!<AT>).)*)<\/AT>/i)

而且它是非贪婪的。


1
你的模式实际上是贪婪的,但它被迫放回它所取的内容以满足匹配。例如,如果“</AT>”后面跟着10,000个“x”,则捕获将匹配所有10,000个字符,然后逐个放弃它们,直到放弃“</AT>”,然后才能匹配模式的结尾。 /<AT>((?:(?!<\/AT>).)*)<\/AT>/i/<AT>((?:(?!<\/?AT>).)*)<\/AT>/i 将防止过度匹配和回溯。 更有效的编写方式是 /<AT>((?:[^<]*|<(?!\/?AT>))*)<\/AT>/,它避免了为每个即将匹配的字符测试否定前瞻。 - Ven'Tatsu

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