我有一个字符串1/temperatoA,2/CelcieusB!23/33/44,55/66/77
,我想提取单词temperatoA
和CelcieusB
。
我有这个正则表达式(\d+/(\w+),?)*!
,但我只得到匹配1/temperatoA,2/CelcieusB!
为什么?
答案 0 :(得分:8)
您的整个匹配评估为'1/temperatoA,2/CelcieusB'
,因为它与以下表达式匹配:
qr{ ( # begin group
\d+ # at least one digit
/ # followed by a slash
(\w+) # followed by at least one word characters
,? # maybe a comma
)* # ANY number of repetitions of this pattern.
}x;
'1/temperatoA,'
首先完成捕获#1,但是因为你要求引擎捕获尽可能多的捕获它然后返回并发现该模式在'2/CelcieusB'
中重复(逗号不是是必要的)。所以整场比赛就是你所说的,但你可能没想到的是'2/CelcieusB'
将 '1/temperatoA,'
替换为 $1
,因此$1
读取'2/CelcieusB'
。
无论何时你想要捕获某个特定字符串中某个特定模式的内容,最好使用 g lobal标志并将捕获分配到数组中。由于数组不是$1
之类的单个标量,因此它可以保存为捕获#1捕获的所有值。
当我这样做时:
my $str = '1/temperatoA,2/CelcieusB!23/33/44,55/66/77';
my $regex = qr{(\d+/(\w+))};
if ( my @matches = $str =~ /$regex/g ) {
print Dumper( \@matches );
}
我明白了:
$VAR1 = [
'1/temperatoA',
'temperatoA',
'2/CelcieusB',
'CelcieusB',
'23/33',
'33',
'55/66',
'66'
];
现在,我认为这可能不是你所期望的。但是'3'
和'6'
是字符,所以 - 在斜线后面 - 它们符合表达式。
因此,如果这是一个问题,您可以将正则表达式更改为等效的:qr{(\d+/(\p{Alpha}\w*))}
,指定第一个字符必须是 alpha ,后跟任意数量的单词字符。然后转储看起来像这样:
$VAR1 = [
'1/temperatoA',
'temperatoA',
'2/CelcieusB',
'CelcieusB'
];
如果您只想要'temperatoA'
或'CelcieusB'
,那么您捕获的内容超出了您的需要,并且您希望正则表达式为qr{\d+/(\p{Alpha}\w*)}
。
但是,捕获表达式中捕获多个块的秘诀是将匹配分配给数组,然后可以对数组进行排序以查看它是否包含所需的数据。
答案 1 :(得分:1)
这里的问题是:你为什么使用一个明显错误的正则表达式?你是怎么得到它的?
您想要的表达式如下:
(\w+)
答案 2 :(得分:1)
使用Perl兼容的正则表达式引擎,您可以搜索
(?<=\d/)\w+(?=.*!)
(?<=\d/)
断言在比赛开始前有一个数字和一个斜线
\w+
匹配标识符。这允许字母,数字和下划线。如果您只想允许字母,请改用[A-Za-z]+
。
(?=.*!)
断言字符串前面有一个!
- i。即我们通过!
后,正则表达式将失败。
根据您使用的语言,您可能需要转义正则表达式中的某些字符。
电子。例如,要在C(使用PCRE库)中使用,您需要转义反斜杠:
myregexp = pcre_compile("(?<=\\d/)\\w+(?=.*!)", 0, &error, &erroroffset, NULL);
答案 3 :(得分:0)
这会有用吗?
/([[:alpha:]]\w+)\b(?=.*!)
我做了以下假设......
[[:alpha:]]
匹配任何字母字符。
\b
匹配字边界。
而(?=.*!)
来自Tim Pietzcker's post。