R正则表达式(相关词语)

4
我想知道如何使用正则表达式选择相互接近的单词,例如,我想从以下短语中选择数字和单词“miles”:
"140,000 mostly freeway miles" 
"173k commuter miles. "       
"154K(all highway) miles

我不知道如何填写中间的可选单词:

[0-9]+ ???? miles

*p near* 可以被定义为相距 1-3 个单词。感谢指出。

1
“near”是什么意思?您想限制它们之间的字符或单词数量吗?还是它们可以任意远离? - Martin Ender
附近可能相隔1-3个单词 - user1103294
你在使用什么语言来编写正则表达式?为什么需要选择单词“miles”,当你知道它总是存在的? - FixMaker
@Lorax R 是一门编程语言 ;) - Martin Ender
@m.buettner - 哎呀!我的错,我漏掉了那个。下次教训我不要这么快地浏览问题标题 :-) - FixMaker
4个回答

3

这里是一个用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"    

这表示组号加标点,或是在第一组中加入字母k。紧接着可以跟上任何字符。然后是第二组,其中包含单词"miles",后面还可以跟上其他字符。
您也可以使用“正常”的正则表达式语法:
gsub('([0-9,k]+).*(miles).*', 
     '\\1 \\2', 
     x,
     ignore.case=TRUE)

然而,我建议先清洗数据,然后进行一些简单的匹配!例如使用tolower函数并删除标点符号。


这忽略了一个重点,即必须在1到3个单词之间。随意复制我的正则表达式,并使其适用于R,然后我将删除我的答案。 - Martin Ender
我会坚持在我的帖子底部的注释。如果“miles”距离超过3个单词时不应包括在内,则正则表达式会变得过于复杂! - Justin

1

在问题领域中还有许多未解答的问题。除此之外,让我们使用以下数据,其中包含问题中提供的样本数据以进行正匹配,并使用一些附加的样本数据进行负匹配(我正在使用R版本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被添加为负匹配,因为问题将“附近”定义为相隔1-3个单词,而这个短语中没有任何“附近的单词”。

如果我们使用以下...

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在他的answer中建议的那样,先清理数据,然后进行一些更简单的匹配

您可以按以下方式规范化数据:

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的内容:
[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] ""

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

更多信息,请参见:


0
请使用此正则表达式:\d+([.,]\d+)?(?=.*?miles)

你会用 R 怎么写这个? - Justin
@Justin,我猜如果你使用类Perl的正则表达式就可以立即工作。 - Martin Ender
第一个括号放错了位置。使用 gsub("\\d+([.,]\\d+)?(?=.*?miles)", "\\1 \\2", x, perl=TRUE),得到 ",000 mostly freeway miles" " k commuter miles. "。在 R 中,你需要对正则表达式模式中的反斜杠进行双重转义。 - IRTFM

0

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

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

请注意,您应该使此正则表达式不区分大小写,以匹配kK
另请注意,数字部分肯定可以改进。这个只会取第一个数字,然后包括尽可能多的数字、逗号和句点,无论是否构成有效的数字格式。

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