【问题标题】:Regex matching a word with numbers in it正则表达式匹配一个带有数字的单词
【发布时间】:2011-03-10 16:19:14
【问题描述】:

我使用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”。

任何帮助都会很棒。

【问题讨论】:

  • 学习使用并喜欢 x 正则表达式修饰符,它允许您在正则表达式中使用空格(空格、制表符、换行符)进行格式化
  • @Eric Strom 我完全计划这样做;在我尝试解释它的作用之前,我宁愿让它工作:)
  • 这就是重点。如果你能看到它的作用,它就会更容易工作!

标签: regex perl


【解决方案1】:

你们都把这种方法弄得太复杂了。原始正则表达式匹配仅由字母或数字(整数、浮点数,包括指数符号)组成的单词。

如果你需要匹配由字母和数字组成的单词,那么正则表达式就是[a-zA-Z\d]+。根据模块文档,您还需要指定要跳过的内容,并且与 [^a-zA-Z\d]+ 匹配。

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

如果您需要识别模块文档在其示例中显示的数字,请告诉我,我很乐意为您重新添加。根据您的描述,这听起来不像您需要的。

【讨论】:

    【解决方案2】:

    (?&lt;=...)(?=...) 结构是后视和前瞻表达式,它们匹配的文本包含在整个正则表达式匹配的文本中。

    作为一个更简单的例子,对于$_ = "A1X",正则表达式

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

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

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

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

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

    【讨论】:

    • 当然,它不会总是只有 3 个字符;这就是为什么我试图让它更通用。
    【解决方案3】:

    所以看起来您有几件事要解决。如果我理解您的意思,将单词分成不同标记的问题很容易:只需使用非捕获组。如果您不想围绕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 抱怨“未实现可变长度后视”
    • @gms8994 - 啊,真不幸。还是可以的,只是时间长一些。试试这个:p{L}+(?:\d*\.)?\d+(?:[eE][-+]?\d+)?p{L}+|(?&lt;!p{L})(?:\d*\.)?\d+(?:[eE][-+]?\d+)?(?!p{L}) 应该做同样的事情。
    【解决方案4】:

    试试这个:

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

    但是请注意,这个正则表达式(和原来的)将匹配单词“边缘”上的数字。

    【讨论】:

    • 附注这只是 mob 解决方案的改进。它将前两种选择合二为一。
    猜你喜欢
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 2017-12-17
    • 2011-10-15
    相关资源
    最近更新 更多