使用正则表达式匹配包含数字的单词

4
我正在使用Text::Ngrams来确定字符串中的单词组合。但是,我需要保留其中包含数字的单词。我已经确定$o->{tokenrex}需要进行修改,但是我无法确定正确的正则表达式。
原始的正则表达式是qr/([a-zA-Z]+|(\d+(\.\d+)?|\d*\.\d+)([eE][-+]?\d+)?)/;,但我认为我需要更接近这样的东西:
 qr/([a-zA-Z]+|(?<=\w)(\d+(\.\d+)?|\d*\.\d+)([eE][-+]?\d+)?(?=\w)|(\d+(\.\d+)?|\d*\.\d+)([eE][-+]?\d+)?)/;

如果我正确理解了正则表达式,它应该匹配任意数量的字母字符,或者在一个“数字”前后有单词字符的情况下匹配,“数字”。但实际上,它将我的“单词”拆分成了单独的标记。我正在处理的示例单词是A1X。如有帮助,请指教。

3
学习使用并喜欢 x 正则表达式修饰符,它允许您在正则表达式中使用空格(空格、制表符、换行符)进行格式化。 - Eric Strom
@Eric Strom 我完全打算这样做;不过在我尝试解释它的作用之前,我更希望让它能够正常运行 :) - Glen Solsberry
这正是关键。如果你能看到它的运行情况,那么让它工作起来就更容易了! - ridgerunner
4个回答

4

你们把这个问题想得太复杂了。原始正则表达式匹配仅由字母或数字(整数、浮点数,包括指数表示法)组成的单词。

如果你需要匹配既包含字母又包含数字的单词,则正则表达式为 [a-zA-Z\d]+。根据模块文档,你还需要指定要跳过的内容,匹配规则为[^a-zA-Z\d]+

$self->{tokenrex} = qr/([a-z\d]+)/i;
$self->{skiprex}  = qr/([^a-z\d]+)/i;

如果您需要像模块文档示例中显示的那样识别数字,请告诉我,我很乐意为您添加此功能。根据您的描述,这似乎不是您需要的功能。

0

看起来你有几件事情需要解决。如果我理解你所说的是什么意思,将单词分成不同的标记的问题很容易解决:只需使用非捕获组。如果你不想在foo周围创建一个新的捕获组,请使用(?:foo);如果你想要,请使用(foo)

无论如何,你所期望的模式听起来像是这样:

p{L}*(?:\d*\.)?\d+(?:[eE][-+]?\d+)?(?:(?<=p{L}(?:\d*\.)?\d+(?:[eE][-+]?\d+)?)p{L}+)?

解释:

p{L}*                 #Zero or more letter characters (note that this is broader than [a-zA-Z], as it allows accent marks and so forth)
(?:\d*\.)?\d+         #Slightly simplified version of your number-matching pattern
(?:(?<=p{L}...)p{L}+)? #Optionally match trailing letters, but only if there are letters at the beginning

希望我理解了你所需要的内容。一个问题是 [eE];这会引入一些歧义。例如,如果你得到一个像A3E4D这样的字符串,E 是作为字母还是指数?我有一些关于此的想法,但这将更加冗长和复杂。让我知道规则是什么,我会进行编辑,我只是不想在确定你所需的内容之前使事情更加混乱。

在我们的情况下,至少可以假设你例子中的E是一个字母,而不是指数。另外,上面的正则表达式会导致Perl抱怨“未实现可变长度回顾”。 - Glen Solsberry
@gms8994 - 噢,那很不幸。这仍然可以做到,只是会更长。试试这个:p{L}+(?:\d*\.)?\d+(?:[eE][-+]?\d+)?p{L}+|(?<!p{L})(?:\d*\.)?\d+(?:[eE][-+]?\d+)?(?!p{L})应该基本相同。 - Justin Morgan

0

(?<=...)(?=...)是回顾和前瞻表达式,它们匹配的文本不会包含在整个正则表达式匹配的文本中。

举个简单的例子,对于$_ = "A1X",正则表达式:

qr/(?<=A)1(?=X)/

匹配字符串$_,但是表达式匹配的文本(比如在$&中)只是1,而不是A1X

你可以在原始表达式中添加另一个子句:

qr/([a-zA-Z]+|[a-zA-Z][a-zA-Z0-9]+[a-zA-Z]|(\d+(\.\d+)?|\d*\.\d+)([eE][-+]?\d+)?)/

(这将匹配A1B2C3D,但不清楚您是否希望它这样做)


当然,它不总是只有3个字符;这就是为什么我试图使它更通用的原因。 - Glen Solsberry

0

试试这个:

qr/(\b[a-zA-Z]([a-zA-Z\d]+[a-zA-Z])?\b|(\d+(\.\d+)?|\d*\.\d+)([eE][-+]?\d+)?)/

请注意,这个正则表达式(以及原始的正则表达式)会匹配单词“边缘”上的数字。

这只是mob解决方案的一个改进。它将前两个选择合并为一个。 - ridgerunner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接