【问题标题】:Mask phone number in RR中的屏蔽电话号码
【发布时间】:2021-12-30 00:34:52
【问题描述】:

我的原始数据有很多个人信息,所以我在R中屏蔽了它们。示例数据和我的原始代码如下:

install.packages("stringr")
library(string)

x = c("010-1234-5678",
      "John 010-8888-8888",
      "Phone: 010-1111-2222",
      "Peter 018.1111.3333",
      "Year(2007,2019,2020)",
      "Alice 01077776666")

df = data.frame(
  phoneNumber = x
)

pattern1 = "\\d{3}-\\d{4}-\\d{4}"
pattern2 = "\\d{3}.\\d{4}.\\d{4}"
pattern3 = "\\d{11}"

delPhoneList1 <- str_match_all(df, pattern1) %>% unlist
delPhoneList2 <- str_match_all(df, pattern2) %>% unlist
delPhoneList3 <- str_match_all(df, pattern3) %>% unlist

我从数据集中找到了三种模式,每种结果如下:

> delPhoneList1
[1] "010-1234-5678" "010-8888-8888" "010-1111-2222"
> delPhoneList2
[1] "010-1234-5678" "010-8888-8888" "010-1111-2222" "018.1111.3333" "007,2019,2020"
> delPhoneList3
[1] "01077776666"

Pattern1 是我所在国家/地区使用破折号的典型电话号码类型,但有人使用逗号键入诸如 pattern2 之类的号码。但是,pattern2 也包含 pattern1,因此它会像年份系列一样检测其他模式。这是一个意想不到的结果。

我的问题是如何匹配我定义的确切模式。模式2包含过多的模式,例如"007,2019,2020" from "Year(2007,2019,2020)"

此外,下一步是使用以下代码屏蔽数字:

for (phone in delPhoneList1) {
  df$phoneNumber <- gsub(phone, "010-9999-9999", df$phoneNumber)
}

我认为代码对我来说是完美的,但如果你有更有效的方法,请告诉我。

谢谢。

【问题讨论】:

  • 根据您问题顶部的 6 个示例电话号码,您想要的实际屏蔽输出是什么?
  • 为什么不只是df$phoneNumber &lt;- gsub("(\\d{3}-\\d{4}-\\d{4})|(\\d{3}\\.\\d{4}\\.\\d{4})|(\\d{11})", "010-9999-9999", df$phoneNumber)
  • @ekoam OMG。非常感谢!!!我是 R 的初学者,所以我不知道编写代码的有效方法。你解决了我的两个问题,一个是在d{3}后面加\\的模式问题,另一个是短版。
  • 仅供参考,pattern2 中的 . 匹配“任何字符”。相反,将其转义,如pattern2 = "\\d{3}\\.\\d{4}\\.\\d{4}",它将仅匹配句点。或者更好的是,pattern2 = "\\d{3}[-.]\\d{4}[-.]\\d{4}" 将在一个正则表达式中涵盖模式 1 和 2。

标签: r stringr


【解决方案1】:

一个模式来统治他们所有;-)

ptn <- "\\b\\d{3}([-.]?)\\d{4}\\1\\d{4}\\b"
grepl(ptn, x)
# [1]  TRUE  TRUE  TRUE  TRUE FALSE  TRUE
  • 您的pattern2 失败的原因是它使用. 作为分隔符,但在正则表达式中表示“任何字符”。您可以使用\\. 而不是.,它的表现会更好。

  • 我在这里使用占位符:如果第一个分隔符是-,那么\\1 确保另一个分隔符相同。如果它是空的,那么第二个也是空的。这也允许pattern3的11个不间断号码。

  • \\b 是单词边界,向我们保证 12 位数字匹配:

    grepl(ptn, c("12345678901", "123456789012"))
    # [1]  TRUE FALSE
    

由于它有一个占位符,它往往会与stringr:: 函数混淆,但我们可以根据您的需要解决这个问题。

例如,如果您将占位符替换为相同模式的第二个实例,则它可能允许123-4444.5555(混合分隔符),如果这不是问题的话。

ptn2 <- "\\b\\d{3}[-.]?\\d{4}[-.]?\\d{4}\\b"
unlist(str_match_all(x, ptn2))
# [1] "010-1234-5678" "010-8888-8888" "010-1111-2222" "018.1111.3333" "01077776666"  

或者我们可以利用匹配的模式数量(原始ptn):

unlist(str_match(x, ptn)[,1])
# [1] "010-1234-5678" "010-8888-8888" "010-1111-2222" "018.1111.3333" NA              "01077776666"  

【讨论】:

  • 感谢您的详细解答。我不知道 . 作为“任何字符”的含义。也许,我认为没有人使用混合分隔符,但你的提示让我提升了我在 R 中的技能。:D
  • 仅供参考,如果您使用stringr 来处理事情,您将受益于学习至少一些关于正则表达式的知识。 stackoverflow.com/a/22944075/3358272 有一个很好的参考列表,展示了正则表达式的复杂性。虽然我不认为它是一个很棒的教程(还有其他很棒的资源),但它是一个很好的参考。 (而且我确实认为一个简短的教程可能会对您有所帮助,即使通过具体的示例和定义来巩固您已经知道的一些知识。)
  • 感谢您的补充意见。该链接对我来说非常有用,我可以学习更多的正则表达式。详细来说,我面临一个新的问题来解决另一个匹配问题,但我可以彻底理解\\b的含义。再次感谢,新年快乐! :D
猜你喜欢
  • 2018-05-04
  • 2012-07-24
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 2012-09-30
  • 2018-05-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多