【问题标题】:in R, use gsub to remove all punctuation except period在 R 中,使用 gsub 删除除句点之外的所有标点符号
【发布时间】:2014-02-27 07:48:13
【问题描述】:

我是 R 新手,所以希望你能帮助我。

我想使用 gsub 删除除句点和减号之外的所有标点符号,以便我可以在数据中保留小数点和负号。

示例

我的数据框 z 有以下数据:

     [,1] [,2]   
[1,] "1"  "6"    
[2,] "2@"  "7.235"
[3,] "3"  "8"    
[4,] "4"  "$9"   
[5,] "£5" "-10" 

我想使用gsub("[[:punct:]]", "", z) 删除标点符号。

电流输出

> gsub("[[:punct:]]", "", z)
     [,1] [,2]  
[1,] "1"  "6"   
[2,] "2"  "7235"
[3,] "3"  "8"   
[4,] "4"  "9"   
[5,] "5"  "10" 

不过,我希望保留“-”符号和“.”。签名。

期望的输出

 PSEUDO CODE:  
> gsub("[[:punct:]]", "", z, except(".", "-") )
         [,1] [,2]  
    [1,] "1"  "6"   
    [2,] "2"  "7.235"
    [3,] "3"  "8"   
    [4,] "4"  "9"   
    [5,] "5"  "-10" 

有什么想法可以让某些字符免于 gsub() 函数吗?

【问题讨论】:

  • 相信这篇文章会回答你的问题:stackoverflow.com/questions/8697079/…
  • 尝试双重否定,例如:gsub("[^[:^punct:].]", "", x, perl = TRUE)。
  • “z”是matrix 还是data.frame?

标签: r regex replace gsub


【解决方案1】:

你可以试试这个代码。我发现它很方便。

x <- c('6,345', '7.235', '8', '$9', '-10')
gsub("[^[:alnum:]\\-\\.\\s]", "", x)

[1] "6345"  "7.235" "8"     "9"     "-10"

x <- c('1', '2@', '3', '4', '£5')
gsub("[^[:alnum:]\\-\\.\\s]", "", x)

[1] "1" "2" "3" "4" "5"

此代码{gsub("[^[:alnum:]]", "", x))} 删除不包含字母数字术语的所有内容。然后我们添加到例外列表中。这里我们添加连字符(\-)、句号(\.) 和空格(\s) 得到gsub("[^[:alnum:]\-\.\s]", "", x)。现在它会删除所有不是字母数字、连字符、句号和空格的内容。

【讨论】:

  • 你能解释一下你的代码的更多细节吗?
  • 添加了解释和一个例子。
【解决方案2】:

以下是在 R 中使用基本 R (g)sub 和 stringr 删除/替换函数限制通用字符类的一些选项:

(g)sub 与 perl=TRUE

您可以将[[:punct:]] 括号表达式与[:punct:] POSIX 字符类一起使用,并使用(?!\.) 负前瞻来限制它,这将要求右侧紧随其后的字符不等于.:

(?!\.)[[:punct:]]      # Excluding a dot only
(?![.-])[[:punct:]]    # Excluding a dot and hyphen

要匹配一个或多个匹配项,请使用非捕获组对其进行包装,然后将+ 量词设置为该组:

(?:(?!\.)[[:punct:]])+   # Excluding a dot only
(?:(?![.-])[[:punct:]])+ # Excluding a dot and hyphen

请注意,当您删除找到匹配项时,两个表达式将产生相同的结果,但是,当您需要替换为其他字符串/字符时,量化将允许使用一次替换模式来更改整个连续的字符块。

带有stringr替换/删除功能

在详细介绍之前,请注意与 (g)sub 一起使用的 PCRE [[:punct:]] 不会匹配由 ICU regex library 提供支持的 stringr 正则表达式函数中的相同字符。您需要改用[\p{P}\p{S}],请参阅R/regex with stringi/ICU: why is a '+' considered a non-[:punct:] character?

ICU 正则表达式库有一个很好的功能,可以与字符类一起使用,称为 character class subtraction。

因此,您编写了您的字符类,例如所有标点匹配类,例如 [\p{P}\p{S}],然后您想要“排除”(=减去)一个字符或两个或三个字符,或者字符的整个子类。您可以使用两种表示法:

[\p{P}\p{S}&&[^.]]   # Excluding a dot
[\p{P}\p{S}--[.]]    # Excluding a dot
[\p{P}\p{S}&&[^.-]]  # Excluding a dot and hyphen
[\p{P}\p{S}--[.-]]   # Excluding a dot and hyphen

要使用这种方法匹配 1+ 个连续出现,您不需要任何包装组,只需使用 +:

[\p{P}\p{S}&&[^.]]+  # Excluding a dot
[\p{P}\p{S}--[.]]+   # Excluding a dot
[\p{P}\p{S}&&[^.-]]+  # Excluding a dot and hyphen
[\p{P}\p{S}--[.-]]+   # Excluding a dot and hyphen

见R demo tests with outputs:

x <- "Abc.123#&*xxx(x-y-z)???? some@other!chars."

gsub("(?!\\.)[[:punct:]]", "", x, perl=TRUE)
## => [1] "Abc.123xxxxyz someotherchars."
gsub("(?!\\.)[[:punct:]]", "~", x, perl=TRUE)
## => [1] "Abc.123~~~xxx~x~y~z~~~~~ some~other~chars."
gsub("(?:(?!\\.)[[:punct:]])+", "~", x, perl=TRUE)
## => [1] "Abc.123~xxx~x~y~z~ some~other~chars."

library(stringr)
stringr::str_remove_all(x, "[\\p{P}\\p{S}&&[^.]]") # Same as "[\\p{P}\\p{S}--[.]]"
## => [1] "Abc.123xxxxyz someotherchars."
stringr::str_replace_all(x, "[\\p{P}\\p{S}&&[^.]]", "~")
## => [1] "Abc.123~~~xxx~x~y~z~~~~~ some~other~chars."
stringr::str_replace_all(x, "[\\p{P}\\p{S}&&[^.]]+", "~")  # Same as "[\\p{P}\\p{S}--[.]]+"
## => [1] "Abc.123~xxx~x~y~z~ some~other~chars."

【讨论】:

    【解决方案3】:

    另一种思考方式是您想保留什么?您可以使用正则表达式来保留和省略信息。我有很多数据帧,我需要一次性清除单元并从多行转换,我发现在这些情况下使用apply 系列中的东西最容易。

    重新创建示例:

    a <- c('1', '2@', '3', '4', '£5')
    b <- c('6', '7.235', '8', '$9', '-10')
    z <- matrix(data = c(a, b), nrow = length(a), ncol=2)
    

    然后将apply 与gsub 结合使用。

    apply(z, 2, function(x) as.numeric(gsub('[^0-9\\.\\-]', '', x)))
          [,1]    [,2]
    [1,]    1   6.000
    [2,]    2   7.235
    [3,]    3   8.000
    [4,]    4   9.000
    [5,]    5 -10.000
    

    这指示 R 匹配除数字、句点和连字符/破折号以外的所有内容。就个人而言,我发现它在这些情况下更清洁、更容易使用,并提供相同的输出。

    此外,文档对这些强大但令人困惑的正则表达式有很好的解释。

    https://stat.ethz.ch/R-manual/R-devel/library/base/html/regex.html

    或?regex

    【讨论】:

    • 该链接只是托管 R 文档。使用?regex 可以看到相同的内容。
    【解决方案4】:

    您可以像这样放回一些匹配项:

     sub("([.-])|[[:punct:]]", "\\1", as.matrix(z))
         X..1. X..2.  
    [1,] "1"   "6"    
    [2,] "2"   "7.235"
    [3,] "3"   "8"    
    [4,] "4"   "9"    
    [5,] "5"   "-10"  
    

    我在这里保留. 和-。

    我猜,下一步是强制你得到一个数字矩阵,所以在这里我将这两个步骤结合起来:

    matrix(as.numeric(sub("([.-])|[[:punct:]]", "\\1", as.matrix(z))),ncol=2)
       [,1]    [,2]
    [1,]    1   6.000
    [2,]    2   7.235
    [3,]    3   8.000
    [4,]    4   9.000
    [5,]    5 -10.000
    

    【讨论】:

    • 感谢您,完美运行。我只需要第一部分。你能解释一下这里发生了什么吗?就像我理解你正在分离 .和 - 来自:punct: 但不确定如何..
    • \\1 是使用 () 的正则表达式中最后一次捕获的语法它表示任何匹配的内容,用它替换它。我只放了“。”和组 () 中的“-”,因此 \\1 将替换 .-(由相同的值),因此将它们保留在此处。
    • @CrayonConstantinople 我不确定我的“英语”解释是否正确,也许更好地阅读关于组捕获的信息here。
    • 感谢您的帮助。出于兴趣,是否需要进行很多更改才能将其更改为 data.frame 而不是矩阵?
    • @CrayonConstantinople 只需在此应用as.data.frame。
    猜你喜欢
    • 2012-01-31
    • 1970-01-01
    • 1970-01-01
    • 2017-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多