【问题标题】:Remove US zip codes from a string: R regex从字符串中删除美国邮政编码:R regex
【发布时间】:2014-08-09 22:40:12
【问题描述】:

我正在尝试从字符串中删除/提取邮政编码。逻辑是我正在抓取的东西是:

  1. 必须恰好包含 5 个连续数字或
  2. 必须包含 5 个连续数字,后跟一个短划线,然后是 4 个连续数字或
  3. 必须包含 5 个连续数字,后跟一个空格,然后是 4 个连续数字

字符串的 zip 部分可以以空格开头,但也可以不。

这是 MWE 和我尝试过的。 2 个尝试的正则表达式基于 this questionthis question

text.var <- c("Mr. Bean bought 2 tickets 2-613-213-4567",
  "43 Butter Rd, Brossard QC K0A 3P0 – 613 213 4567", 
  "Rat Race, XX, 12345",
  "Ignore phone numbers(613)2134567",
  "Grab zips with dashes 12345-6789 or no space before12345-6789",  
  "Grab zips with spaces 12345 6789 or no space before12345 6789",
  "I like 1234567 dogs"
)

pattern1 <- "\\d{5}([- ]*\\d{4})?"
pattern2 <- "[0-9]{5}(-[0-9]{4})?(?!.*[0-9]{5}(-[0-9]{4})?)"


regmatches(text.var, gregexpr(pattern1, text.var, perl = TRUE)) 
regmatches(text.var, gregexpr(pattern2, text.var, perl = TRUE)) 

## [[1]]
## character(0)
## 
## [[2]]
## character(0)
## 
## [[3]]
## [1] "12345"
## 
## [[4]]
## [1] "21345"
## 
## [[5]]
## [1] "12345-6789"
## 
## [[6]]
## [1] "12345"
## 
## [[7]]
## [1] "12345"

期望的输出

## [[1]]
## character(0)
## 
## [[2]]
## character(0)
## 
## [[3]]
## [1] "12345"
## 
## [[4]]
## character(0)
## 
## [[5]]
## [1] "12345-6789" "12345-6789"
## 
## [[6]]
## [1] "12345 6789" "12345 6789"
## 
## [[7]]
## character(0)

注意 R 的正则表达式与其他正则表达式类似,但是是 R 特有的。这个问题是 R 的正则表达式特有的,而不是一般的正则表达式问题。

【问题讨论】:

  • 我不确定这张纸条。例如,当您使用 perl=TRUE 时,您也可以使用 perl 正则表达式,因此通常经典的正则表达式是 R 解决方案。
  • @agstudy 更多关于加倍反斜杠和任何其他 R 特定正则表达式的东西(我不太了解正则表达式,不知道这些东西是什么,但我找到了非 R 用户' 正则表达式通常不会转换为 R)。

标签: regex r


【解决方案1】:

环视断言

您可以在此处使用Negative Lookbehind 和单词边界\b 的组合。

regmatches(text.var, gregexpr('(?<!\\d)\\d{5}(?:[ -]\\d{4})?\\b', text.var, perl=T))

说明

  • 否定的lookbehind断言前面的不是数字。
  • 单词边界断言一侧有单词字符,另一侧没有。

    (?<!        # look behind to see if there is not:
      \d        #   digits (0-9)
    )           # end of look-behind
    \d{5}       # digits (0-9) (5 times)
    (?:         # group, but do not capture (optional):
      [ -]      #   any character of: ' ', '-'
      \d{4}     #   digits (0-9) (4 times)
    )?          # end of grouping
    \b          # the boundary between a word character (\w) and not a word character
    

其他选项

您可以考虑使用性能更快的stringi 库包。

> library(stringi)
> stri_extract_all_regex(text.var, '(?<!\\d)\\d{5}(?:[ -]\\d{4})?\\b')

【讨论】:

  • 效果很好。谢谢你。 cmets 也很有帮助!
  • 刚刚看到你有一个正则表达式解释工具:liveforfaith.com/re/explain.pl 非常酷 :-) 我还将这些正则表达式转换成一个快速的 R 包。我想给你这个包的贡献者作者身份,这个包的名字超出了 SO 的 hwnd。如果您想使用您的真实姓名,请发送电子邮件github.com/trinker
【解决方案2】:

您可以像这样使用正则表达式:

"(?<!\\d)(\\d{5}(?:[-\\s]\\d{4})?)\\b"

Working demo

【讨论】:

    【解决方案3】:

    这对我有用,并且在您的所有示例中都给出了所需的输出:

    "(?<!\\d)(\\d{5}(?:[- ]\\d{4})?)(?!\\d)"
    

    【讨论】:

      【解决方案4】:

      带有 LookArounds 的正则表达式:

      (?<![0-9-])([0-9]{5}(?:[ -][0-9]{4})?)(?![0-9-])`  
      

      现场演示:http://regex101.com/r/hU9oK4/1

      我们追求的东西:

      • [0-9]{5} 是最重要的部分,正好是 5 个数字

      • (?:[ -][0-9]{4})?) 可选地后跟 4 个,但仅当用空格或减号连接时

      边界,边界,边界:

      • (?&lt;![0-9-])第一组:Negative LookBehind(确保没有数字或破折号)

      • (?![0-9-]) 最后一组:Negative LookAhead (—||— 相同的模式...)

      额外的测试用例:

      另一个 zip 09788-4234 后面没有空格
      98712
      987122
      邮编或范围 12987-19222 ?
      这个序列号 88101-8892-22912-9991-99101 怎么样?
      90872-8881

      为什么?

      • Lo​​okArounds 不包含consume 字符
      • 您不应该选择误报(例如,更长的编号中的前 5 位或后 5 位数字。)
      • ZIP 可能位于单独的一行,或者位于开头或结尾
      • 你可能会碰到一个无空格地址
      • 以减号开头的 5 位数字不应是邮政编码

      最后说明:这不是一个最终或防弹匹配代码,您可能仍会收集一些类似 zip 的代码,尤其是因为您要求的数字组之间的空间

      个人说明:我发现 [0-9] 字符类对于 RegEx 的新手来说更清晰更容易理解,即使它们包含在 \d 中,但它们也更快,并且在 RegEx 风格之间具有更好的兼容性。另一方面,双重转义(例如\\d 读起来很丑)

      【讨论】:

      • R 中需要双转义
      • @hwnd 确实是 [0-9] 绕过需要双重转义 \d
      【解决方案5】:

      qdapRegex 包具有rm_zip 函数(基于@hwnd 的响应):

      rm_zip(text.var)
      rm_zip(text.var, extract=TRUE)
      
      > rm_zip(text.var, extract=TRUE)
      [[1]]
      [1] NA
      
      [[2]]
      [1] NA
      
      [[3]]
      [1] "12345"
      
      [[4]]
      [1] NA
      
      [[5]]
      [1] "12345-6789" "12345-6789"
      
      [[6]]
      [1] "12345 6789" "12345 6789"
      
      [[7]]
      [1] NA
      

      【讨论】:

        猜你喜欢
        • 2021-03-07
        • 2013-10-09
        • 1970-01-01
        • 1970-01-01
        • 2019-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-04
        相关资源
        最近更新 更多