0

我正在尝试使用正则表达式从分号分隔的字符串中删除令牌。示例字符串如下所示:

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;

但我仍然想知道为什么我不能告诉表达式只匹配第一个分号......

4

2 回答 2

4

当你使用像+or之类的量词时*,它们是贪婪的。他们吞噬尽可能多的角色,并且只有在被迫回溯时才将其归还。因此,该模式.*;将匹配所有内容,直到最后一个分号。

也许贪婪的量词应该节食。我们可以通过使用惰性版本来强制它们:+?*?. 这些将尽早终止。所以模式将是:

/Uid=.+?;/  # repeat for Pwd

匹配到第一个分号

这是可行的,但在类中使用否定字符类而不是非贪婪量词被认为是一种很好的风格.

/Uid=[^;]+;/

因为这可能出错的方法更少(比如删除该行的其余部分)。它也比其他解决方案更明确。

于 2013-08-29T19:31:27.493 回答
3

如果您不想使用否定字符类(适用于大多数正则表达式包),您可以使用非贪婪量词来匹配关键字后面的数据(但它仅适用于与 Perl 兼容的正则表达式包)。有关详细信息,请参阅正则表达式下的量词。

$mystring =~s /Uid=.+?;//i;

额外的问号使+非贪婪;它采用将匹配的最小字符串而不是最大值,因此它不会匹配任何分号。

于 2013-08-29T19:27:36.663 回答