【问题标题】:R regex to extract information from stringR 正则表达式从字符串中提取信息
【发布时间】:2015-03-18 04:52:53
【问题描述】:

有人告诉我,R 是一个很好的数据处理工具。所以我想弄清楚是否可以(容易)用 R 进行正则表达式数据提取。

以下是从 Python 中提取两个关键信息的示例:

import re

str = "oh, 100.0 dollar is 621.5 yuan"
m = re.search("([\d+\.\d+]+).*?([\d+\.\d+]+)",str)
if m:
    print m.group(1),"->",m.group(2)

Python 的输出是:

100.0 -> 621.5

Python 的结果真的很酷,但是如何在 R 中有效地做到这一点?

【问题讨论】:

标签: python regex r


【解决方案1】:

当然。使用基本 R 或其众多软件包之一也很容易实现这样的事情。这是一个“stringi”包的例子。

library(stringi)
m <- stri_extract_all_regex(str, "\\d+\\.\\d")[[1]]
sprintf("%s -> %s", m[1], m[2])
# [1] "100.0 -> 621.5"

上述的基本 R 等效项可能是使用 gregexprregmatches

regmatches(str, gregexpr("\\d+\\.\\d+", str))[[1]]
# [1] "100.0" "621.5"

【讨论】:

  • 我本来打算和stri_match_all一起去的,但这一样好:)
  • 本例中两个模式是一样的,如果是不同的模式呢?比如第一个匹配数字,第二个匹配字符串?
  • @Beatlej,那么您需要提供更具体的正则表达式,也许在您的模式中使用 | 来指定选项。
  • @Beatlej 你需要使用交替。即\\d+(?:\\.\\d+)?| ( ... )
【解决方案2】:

嗯,您的正则表达式不正确,并且符合您的预期。 character class 定义了一组字符。说——“匹配类指定的一个字符”。

因此,它匹配以下内容:

[\d+\.\d+]+   # any character of: digits (0-9), '+', '\.', digits (0-9), '+' 
              # (1 or more times)

使用基础 R,您可以使用 regmatchesgregexpr 与以下模式:

x <- 'oh, 100.0 dollar is 621.5 yuan'
m <- regmatches(x, gregexpr('\\d+(?:\\.\\d+)?', x, perl=T))[[1]]
paste(m[1], '->', m[2])
# [1] "100.0 -> 621.5"

正则表达式(解释

\d+           # digits (0-9) (1 or more times)
(?:           # group, but do not capture (optional):
  \.          #   '.'
  \d+         #   digits (0-9) (1 or more times)
)?            # end of grouping

【讨论】:

  • 很好,但如果不匹配,m[1] 和 m[2] 是什么?
  • 何不试试看呢?
【解决方案3】:

这里有一些方法。其他的也可以使用各种其他包。

1) 可以用strapply 在一行中完成(尽管为了便于阅读,我们将它分成两行)。 strapply 将模式pat 应用于字符串str,然后将捕获的字符串输入到函数中(此处以公式表示法表示)并返回结果:

library(gsubfn)

# test data
str <- "oh, 100.0 dollar is 621.5 yuan"

pat <- "([\\d+\\.\\d+]+).*?([\\d+\\.\\d+]+)"   
strapply(str, pat, ~ paste(x, "->", y), simplify = TRUE)

给予:

[1] "100.0 -> 621.5"

注意,我们使用了与问题中相同的正则表达式来表明 Python 正则表达式在 R 中也可以工作(尽管我们在写出它时需要将反斜杠加倍,因为“\\”代表一个反斜杠);但是,我们可以改用这个来稍微简化正则表达式:

pat <- "(\\d+\\.\\d+).*?(\\d+\\.\\d+)"   

或者这可能就足够了:

pat <- "([\\d.]+).*?([\\d.]+)"

在接下来的点中,我们使用更简单的正则表达式。

2)我们还可以像这样简化模式,在这种情况下,它可以使用来自同一个包的strapplyc

s <- strapplyc(str, "\\d+\\.\\d+")[[1]]
paste(s[1], "->", s[2])

给出相同的答案。

3) 另一种方法是将输入拆分为单词,然后只保留代表数字的单词。这个不使用任何包:

g <- grep("\\d+\\.\\d+", strsplit(str, " ")[[1]], value = TRUE)
paste(g[1], "->", g[2])

给出相同的答案。

【讨论】:

  • 问题不清楚,但所有答案在str 上给出了相同的结果。
  • 好吧,这就是海报使用的正则表达式,所以我使用相同的正则表达式来表明 python 正则表达式也可以在 R 中工作(模数加倍反斜杠),因为我认为这是问题的重点.我将对此添加注释。
【解决方案4】:

这是gsub 的一系列函数。

> str = "oh, 100.0 dollar is 621.5 yuan"
> sub("[[:space:]]+", " -> ", gsub("^[[:space:]]+|[[:space:]]+$", "", gsub("(\\d+(?:\\.\\d+)?)|\\S", '\\1', str, perl=T)))
[1] "100.0 -> 621.5"

如果输入包含两个以上的数字,请尝试此操作。我只是把上面的sub函数换成了gsub

> str = "oh, 100.0 dollar is 621.5 yuan 700 to 888.78"
> gsub("[[:space:]]+", " -> ", gsub("^[[:space:]]+|[[:space:]]+$", "", gsub("(\\d+(?:\\.\\d+)?)|\\S", '\\1', str, perl=T)))
[1] "100.0 -> 621.5 -> 700 -> 888.78"

[[:space:]]+ POSIX 字符类,匹配一个或多个空格。

【讨论】:

    猜你喜欢
    • 2014-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    相关资源
    最近更新 更多