我正在尝试使用正则表达式从分号分隔的字符串中删除标记。示例字符串如下所示:
Field1=Blah;Field2=Bluh;Field3=Dingdong;Uid=John;Pwd=secret;Field4=lalali
Field1=Blah;Field2=Bluh;Field3=Dingdong;Uid=John;Pwd=secret;Field4=lalali;
所以我想在单独的命令中删除“Uid”和“Pwd”标记,以便不删除任何尾随标记(例如,Field4应保留在结尾)。
我目前的尝试是:
$mystring =~s /Uid=.+;//i;
产生
Field1=Blah;Field2=Bluh;Field3=Dingdong;Field4=lalali
哪个适用于第一行,但不适用于第二行,最后是分号,产生
Field1=Blah;Field2=Bluh;Field3=Dingdong;
并错误地删除了Field4。我试过了很多变种,比如
$mystring =~s /Uid=.+;?//i;
$mystring =~s /Uid=.+;+?//i;
没有成功。我意识到我需要告诉正则表达式只匹配第一个分号,但我无法弄清楚如何。
现在,只是为了让我看起来并不完全愚蠢,我能够通过这样做得到它:
$mystring =~s /Uid=[^;]+;//i;
但是我仍然想知道为什么我不能说这个表达只匹配第一个分号......
答案 0 :(得分:4)
当您使用+
或*
等量词时,他们会贪婪。他们吞噬了尽可能多的角色,只有在他们被迫回溯时才会回馈他们。因此,模式.*;
将匹配所有内容,直到 last 分号。
也许贪婪的量词应该节食。我们可以使用惰性版本强制它们:+?
和*?
。这些将尽早终止。所以模式是:
/Uid=.+?;/ # repeat for Pwd
匹配到第一个分号
这样可行,但是使用带有.
类的非贪婪量词而不是使用否定字符类被认为是好的风格:
/Uid=[^;]+;/
因为这样做的方法可能会更少(比如删除其余部分)。它也比其他解决方案更明确。
答案 1 :(得分:3)
如果您不想使用否定字符类(适用于大多数正则表达式包),您可以使用非贪心量词来匹配关键字后面的数据(但它只适用于Perl兼容的regex包)。有关详细信息,请参阅Regular expressions下的量词。
$mystring =~s /Uid=.+?;//i;
额外的问号使+
非贪婪;它需要匹配的最小字符串而不是最大值,因此它不会匹配任何分号。