尝试提取匹配string中pattern的子字符串。 例如,我有像下面那样的文本
compile("org.springframework.boot:spring-boot-starter-data-jpa")
我希望在斜杠(/)和斜杠之后提取任何东西,但不知何故,我的正则表达式提取第一个子字符串并忽略该行中的其余子字符串。
我的输出如下所示:
[ Pierre/NNP Vinken/NNP ]
,/,
[ 61/CD years/NNS ]
old/JJ ,/, will/MD join/VB
[ the/DT board/NN ]
as/IN
[ a/DT nonexecutive/JJ director/NN Nov./NNP 29/CD ]
./.
[ Mr./NNP Vinken/NNP ]
is/VBZ
[ chairman/NN ]
of/IN
但我真正想要的是下面的内容
tag:Pierre/NNP Vinken - word:Pierre/NNP Vinken/NNP ->1
tag:, - word:,/, ->1
tag:61/CD years - word:61/CD years/NNS ->1
tag:old/JJ ,/, will/MD join - word:old/JJ ,/, will/MD join/VB ->1
tag:the/DT board - word:the/DT board/NN ->1
tag:as - word:as/IN ->1
tag:a/DT nonexecutive/JJ director/NN Nov./NNP 29 - word:a/DT nonexecutive/JJ director/NN Nov./NNP 29/CD ->1
tag:. - word:./. ->1
tag:Mr./NNP Vinken - word:Mr./NNP Vinken/NNP ->1
tag:is - word:is/VBZ ->1
tag:chairman - word:chairman/NN ->1
tag:of - word:of/IN ->1
我使用的代码:
tag:NNP - word:Pierre ->1
tag:NNP - word:Vinken ->1
tag:, - word:, ->1
tag:CD - word:61 ->1
.
.
etc.
任何想法为什么我的正则表达式不应该像
那样编辑:
我正在解析的文本文件中的也有野性字符和标点符号,这意味着文件将具有以下内容: '' /'' " /" ,/, ./。 ?/? !/! 。 。 。 等等
所以我想要捕获所有这些东西,不仅仅是字母和数字字符。
答案 0 :(得分:2)
我认为你有tag/word
tag
和word
可能是一切,除了],[,\s,
之类的字符:
\s*([^\[\]\s]+?)\/([^\[\]\s]+)\s*
^^^^^^^^^1
此正则表达式与您的原始模式类似。 (见DEMO)
说明
1-此捕获组匹配不是.
,[
或]
\s
答案 1 :(得分:1)
围绕整个模式的最外面一组括号被捕获到$1
,这显然不是预期的。此外,.*\/
的贪婪意味着它将所有内容都带到 last /
。同样,.*\s+
只留下最后一个空格。
一种方法是使用否定字符类
my ($word, $tag) = m{ ([^/\s]+) / ([^/\s]+) }x;
模式[^/\s]+
匹配一个或多个连续字符的字符串,每个字符不是/
或空格。所以你得到一个" 字"在/
之前和之后。如果你采取" 之后的任何事情"正如文中所说,在下一次削减之前不清楚应该是什么。
然后你的方法就可以了。
while (my $line = <$fh>)
{
while ( $line =~ m{ ([^/\s]+) / ([^/\s]+) }gx )
{
$tagHash{$2}{$1}++;
}
}
另一个计数似乎无关紧要,所以我把它留下来专注于这个问题。
然而,这里有一点点缺失。
此方法无法检测线条何时与预期格式不同。例如
word1/tag1 word2/tag2/ tag3/word4/tag4
悄悄地产生错误的结果。一些违规行为被忽略,但有许多不良案例。
捕获这一点的一种方法是预处理该行,检查所有斜杠之间至少有两个单词,并且在第一个和最后一个之后至少有一个单词。这意味着每行处理两次,而且它也变得更加混乱。例如
while (my $line = <$fh>)
{
my @parts = split '/', $line;
if (not shift @parts or not pop @parts or grep { 2 > split } @parts) {
warn "Unexpected format: $line";
next;
}
$tagHash{$2}{$1}++ while $line =~ m{ ([^/\s]+) / ([^/\s]+) }gx;
}
此检查会更改@parts
数组,因此如果以后需要该数组,请更好地使用
if (!$parts[0] or !$parts[-1] or grep { 2 > split } @parts[1..@parts-2]) { ...
而不是grep
,也可以使用来自List::Util的短路any
另一种方法是改变方法,仔细解析该行,而不是盲目地跳过正则表达式匹配。由于第一个和最后一个可能只有一个单词,这可能很难用正则表达式。分割和使用数组可能更清晰,更实用。
很难想象格式总是匹配数据,所以我建议考虑其中一些。