【问题标题】:R regular expression (near words)R 正则表达式(靠近单词)
【发布时间】:2012-11-21 19:15:27
【问题描述】:

我想知道如何使用正则表达式选择 彼此靠近的单词。 例如,我想从以下短语中选择数字和单词英里:

"140,000 mostly freeway miles" 
"173k commuter miles. "       
"154K(all highway) miles

中间选词不知道怎么填:

[0-9]+ ???? miles

*near 可以定义为相隔 1-3 个单词。感谢您指出了这一点。

【问题讨论】:

  • 什么是“附近”?你想限制它们之间的字符或单词的数量吗?或者他们可以任意相距很远?
  • near 可能相隔 1-3 个字
  • 您的正则表达式使用什么语言? ...当你知道它会一直存在时,为什么还要选择“英里”这个词?
  • @Lorax R 一种语言 ;)
  • @m.buettner - 哦!我的错,我错过了。那会教我下次不要这么快浏览问题标题:-)

标签: regex r


【解决方案1】:

这是R 中的答案。其他答案可以进行一些修改。大多数情况下,它们需要“双重转义”,并且您必须使用配对函数 regexprregmatches

x=c("140,000 mostly freeway miles" ,"173k commuter miles. " ,"154K(all highway) miles")


gsub('([[:digit:][:punct:]k]+).*(miles).*', 
     '\\1 \\2', 
     x,
     ignore.case=TRUE)

# [1] "140,000 miles" "173k miles"    "154 miles"    

这表示组号标点符号或第 1 组中的 k。在此之后任何内容。然后是第 2 组,即英里这个词,然后是其他任何内容。

您也可以使用“正常”的正则表达式语法:

gsub('([0-9,k]+).*(miles).*', 
     '\\1 \\2', 
     x,
     ignore.case=TRUE)

但是,我会先清理数据,然后再进行一些更简单的匹配! (例如tolower 并删除标点符号)。

【讨论】:

  • 这遗漏了中间必须有 1 到 3 个单词的观点。随意复制我的正则表达式并使其适用于 R,然后我将删除我的答案。
  • 我会在帖子底部留下我的笔记。如果miles 超过 3 个单词时不应该包含在内,那么正则表达式就变得太复杂了!
【解决方案2】:

关于问题域有许多未解决的问题。除此之外,让我们使用以下数据,其中包含问题中提供的样本数据用于正匹配,以及一些附加样本数据用于负匹配(我使用的是R version 2.14.1 (2011-12-22)):

x <- c("140,000 mostly freeway miles", "173k commuter miles. ", "154K(all highway) miles", "1,24 almost but not mostly freeway miles", "1,2,3,4K MILES")

1,2,3,4K MILES 被添加为否定匹配,因为问题将 near 定义为 1-3 words apart,并且它的“邻近词”为零。

如果我们使用以下...

sub('[\\d,]+k?\\s+(([^\\s]+\\s+){1,3})miles', '\\1', x, ignore.case = TRUE, perl = TRUE)

...我们得到:

[1] "mostly freeway "
[2] "commuter . "
[3] "154K(all highway) miles"
[4] "1,24 almost but not mostly freeway miles"
[5] "1,2,3,4K MILES"

可能不是你想要的结果。由于数据未标准化,因此您必须使用会变得非常复杂的正则表达式模式。正如Justin 在他的answerclean up the data first then do some simpler matching 中所建议的那样。

您可以将数据标准化如下:

y <- gsub('\\pP+', ' ', x, perl = TRUE)
y <- gsub('\\s+', ' ', y, perl = TRUE)
y <- gsub('^\\s+|\\s+$', '', y, perl = TRUE)
y <- gsub('(\\d)\\s(?=\\d)', '\\1\\2', y, perl = TRUE)

有关详细信息,请参阅下面的参考资料。这基本上是删除标点符号并确保单词由一个空格分隔。这将为您留下y of:

[1] "140000 mostly freeway miles"
[2] "173k commuter miles"
[3] "154K all highway miles"
[4] "124 almost but not mostly freeway miles"
[5] "1234K MILES"

现在删除与您要查找的内容不匹配的行:

y <- sub('^(?!\\d+k?\\s((?!miles)[^\\s]+\\s){1,3}miles).*$', '', y, ignore.case = TRUE, perl = TRUE)
y
[1] "140000 mostly freeway miles" "173k commuter miles"
[3] "154K all highway miles"      ""
[5] ""

最后,得到“近词”:

y <- sub('^\\d+k?\\s((?!miles)[^\\s]+(\\s(?!miles)[^\\s]+){0,2})\\smiles', '\\1', y, ignore.case = TRUE, perl = TRUE)
y
[1] "mostly freeway" "commuter"       "all highway"    ""
[5] ""

可能有更简单的方法来规范化数据,但这为您提供了一些正则表达式示例。

有关详细信息,请参阅:

【讨论】:

    【解决方案3】:

    使用这个正则表达式\d+([.,]\d+)?(?=.*?miles)

    【讨论】:

    • 你会怎么写R
    • @Justin 我猜如果您使用类似 Perl 的正则表达式,它应该可以立即工作。
    • 第一个括号放错了位置。使用gsub("\\d+([.,]\\d+)?(?=.*?miles)", "\\1 \\2", x, perl=TRUE),得到",000 mostly freeway miles" " k commuter miles. " 。您确实需要在 R 的正则表达式模式中双重转义反斜杠。
    【解决方案4】:

    这仍然有点模糊,但是假设我们将所有内容定义为以空格分隔的“单词”。因此,如果可能有 1-3 个单词,则数字和 miles 之间需要有 2-4 个空格(实际上我会让第一个可选,看你的最后一个例子):

    \d[\d,.]*k?\s*(\S+\s+){1,3}miles
    

    请注意,您应该使此正则表达式不区分大小写,以匹配 kK

    还要注意,数字部分当然可以改进。这将只取第一个数字,然后包含尽可能多的数字、逗号和句点,无论这是否构成有效的数字格式。

    【讨论】:

      猜你喜欢
      • 2019-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-27
      • 2016-05-09
      • 1970-01-01
      • 2016-12-20
      相关资源
      最近更新 更多