我正在尝试在Perl中编写一个正则表达式,它可以处理文本和帐号混合的文本文件。我想要做的是重新格式化帐号。我遇到的问题是,当给定行上有多个匹配项时,使用.*
匹配帐号的任意一侧。我做了一些搜索,找不到任何答案,所以我希望有人可以向我解释我的正则表达式有什么问题所以我可以避免这个陷阱。
while(<>) {
s/(.*)\b([0-9]+)\b(.*)/$1xxx\-$2$3/g;
print;
}
xxx-
将被帐户标识符替换,但在我开始工作之前,我只有x
个。
我遇到的问题是,只有最后一次出现才会被替换而不是所有出现。
例如,使用简单的示例行:
First Part 223456 Third Part Fourth Part 113456 Fifth Part Sixth Part
我希望:
First Part xxx-223456 Third Part Fourth Part xxx-113456 Fifth Part Sixth Part
但我只得到:
First Part 223456 Third Part Fourth Part xxx-113456 Fifth Part Sixth Part
我把它缩小到.*
作为问题如果我在捕获组中包含其他元字符它可以工作但我无法保证文件中的内容所以我需要匹配所有内容。只有在同一行上有多个帐号时才会发生这种情况;如果帐号出现在多行上,它可以正常工作。
非常感谢任何反馈
答案 0 :(得分:2)
如果帐号只是数字,请执行以下操作:
s/\b(\d+)\b/xxx-$1/g;
如果它们总是6个数字,则更具体:s/\b(\d{6})\b/xxx-$1/g;
答案 1 :(得分:2)
(.*)
消耗输入中的所有字符,然后必须开始回溯:返回一个字符并测试下一个模式是否匹配,如果不匹配,则返回另一个字符并检查匹配,字符字符。
因此,通过将贪婪的通用匹配作为您的第一个表达式,您实际上要求引擎仅查找最后一个匹配项。你可能不知道你要求这个,但你是。
通常,在处理正则表达式时,您必须考虑数据:“我如何在文件中识别此模式。很可能,”一个或多个数字“只是不会删除帐号,所以指定您希望匹配的模式,以指定它的最佳能力。 然后你可以确定,如果某些东西与你的模式匹配,那么很可能就是你想要的。顺便说一句,单词边界规范是好开始。
如果您需要完全六位数,请准确指定六个位数。
你不应该指定(.*)
作为比赛的一部分的另一个原因是,从它的外观来看,你正在做你认为你需要做的事情来保持线的其他部分他们的地方。但是,Perl仅用替换替换匹配的部分。您从不需要指定除了您想要匹配的部分之外的任何内容。
因此,假设您的帐号为6位数,这就是您所需要的。
s/\b(\d{6})\b/xxx-$1/g;
最后一点。如果出于某种原因,你的正则表达式会找到第一个匹配项,在模式之后指定(.*)
,保证你只能找到每行一个匹配项,并且/g
不适用,因为它使完全匹配等于输入行。
答案 2 :(得分:1)
我看到的问题是贪婪匹配(.*) which in your case will match everything up until the last ([0-9]word boundary)
。我想你可以关掉它,你应该没事(eg. s/(.*?)//g)
。
这是一个小例子:
while(my $line = <$fh>) {
$line =~ s/(.*?)\b([0-9]+)\b(.*?)/$1xxx\-$2$3/g;
print $line;
}
OUTPUT:
First Part xxx-223456 Third Part Fourth Part xxx-113456 Fifth Part Sixth Part
First Part xxx-223456 Third Part Fourth Part xxx-113456 Fifth Part Sixth Part
First Part xxx-223456 Third Part Fourth Part
First Part xxx-223456
答案 3 :(得分:0)
使用负面后视和另一种积极前瞻的一种方式:
perl -pe 's/(?<!\d)(\d+)(?=\D|$)/xxx-$1/g' <<<"First Part 223456 Third Part Fourth Part 113456 Fifth Part Sixth Part"
它产生:
First Part xxx-223456 Third Part Fourth Part xxx-113456 Fifth Part Sixth Part