我想知道如何使用正则表达式选择彼此靠近的单词。例如,我想从以下短语中选择数字和单词英里:
"140,000 mostly freeway miles"
"173k commuter miles. "
"154K(all highway) miles
中间的选词不知道怎么填:
[0-9]+ ???? miles
*near 可以定义为相隔 1-3 个单词。感谢您指出了这一点。
这是一个答案R
。其他答案可以进行一些修改。大多数情况下,它们需要有“双重转义”,你必须使用成对的函数regexpr
和regmatches
.
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 组中的组号标点符号或 ak。任何内容都遵循此。然后是第 2 组,即英里这个词,然后是其他任何内容。
您还可以使用“普通”正则表达式语法:
gsub('([0-9,k]+).*(miles).*',
'\\1 \\2',
x,
ignore.case=TRUE)
但是,我会先清理数据,然后再进行一些更简单的匹配!(例如tolower
并删除标点符号)。
关于问题域有许多悬而未决的问题。除此之外,让我们使用以下数据,其中包含问题中提供的样本数据用于正匹配和一些附加样本数据用于负匹配(我正在使用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
被添加为否定匹配,因为问题定义为接近,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"
可能不是你想要的结果。由于数据未标准化,因此您必须使用会变得非常复杂的正则表达式模式。正如贾斯汀在他的回答中建议的那样,clean 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
:
[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] ""
可能有更简单的方法来规范化数据,但这为您提供了一些正则表达式示例。
有关详细信息,请参阅:
pcrepattern
手册页。这仍然有点模糊,但是假设我们将所有内容定义为一个由空格分隔的“单词”。因此,如果可能有 1-3 个单词,则数字和之间需要有 2-4 个空格(实际上,我将第一个空格设为可选,请参阅您的最后一个示例)miles
:
\d[\d,.]*k?\s*(\S+\s+){1,3}miles
请注意,您应该使此正则表达式不区分大小写,以匹配k
和K
。
另请注意,数字部分当然可以改进。这个将只取第一个数字,然后包含尽可能多的数字、逗号和句点,无论这是否是有效的数字格式。
使用这个正则表达式\d+([.,]\d+)?(?=.*?miles)