等效的正则表达式,以删除所有标点符号

时间:2013-12-18 18:42:06

标签: regex r perl

在R中,为了从字符串中删除标点符号,我可以这样做:

x <- 'a#,g:?s!*$t/{u}\d\&y'
gsub('[[:punct:]]','',x)
[1] "agstudy"

这很聪明,但我没有严格控制删除的标点符号(想象一下我想在我的角色中保留一些符号)。如何在不忘记任何符号的情况下以更明确的方式重写此gsub,如下所示:

gsub('[#,:?!*$/{}\\&]','',x,perl=FALSE)

修改

我遇到的困难是如何编写正则表达式(我更喜欢在R中)从x中删除所有标点符号,并仅保留#例如:

 "a#gstudy"

5 个答案:

答案 0 :(得分:8)

使用否定先行断言:

x <- 'a#,g:?s!*$t/{u}\\d\\&y'

gsub('(?!#)[[:punct:]]','',x, perl=TRUE)
# [1] "a#gstudy"

这实质上是对每个字符进行两次测试,从前面的字符间空间询问一次下一个字符是否是"#"以外的字符,然后从字符本身询问它是否是标点符号。如果两个测试都为真,则会注册匹配并删除该字符。

答案 1 :(得分:7)

您可以使用否定的字符类,例如:

\pP是标点字符的unicode字符类。

\PP就是不是标点字符。

[^\PP]就是标点符号。

除了代字号之外,

[^\PP~]就是一个标点字符。

注意:您可以使用\p{PosixPunct}

保持ASCII范围

[^\P{PosixPunct}~]

或在\p{XPosixPunct}的ASCII范围内使用具有此特殊性的unicode标点字符:

[^\P{XPosixPunct}~]

答案 2 :(得分:5)

阅读this page表示[[:punct:]]字符应包括:

[-!"#$%&'()*+,./:;<=>?@[\\\]^_`{|}~]

在R ?regex页面上,我们也将此作为验证:

[:punct:]
Punctuation characters:
! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~

因此,您可以将其作为创建自己模式的基础,不包括您想要保留的字符。


这很麻烦,特别是有两个更好的答案,但我只是想表现出我心中的愚蠢:

创建一个如下所示的函数:

newPunks <- function(CHARS) {
  punks <- c("!", "\\\"", "#", "\\$", "%", "&", "'", "\\(", "\\)",
             "\\*", "\\+", ",", "-", "\\.", "/", ":", ";", "<",
             "=", ">", "\\?", "@", "\\[", "\\\\", "\\]", "\\^", "_", 
             "`", "\\{", "\\|", "\\}", "~")
  keepers <- strsplit(CHARS, "")[[1]]
  keepers <- ifelse(keepers %in% c("\"", "$", "{", "}", "(", ")",
                                   "*", "+", ".", "?", "[", "]",
                                   "^", "|", "\\"), paste0("\\", keepers), keepers)
  paste(setdiff(punks, keepers), collapse="|")
}

用法:

gsub(newPunks("#"), "", x)
# [1] "a#gstudy"
gsub(newPunks(""), "", x)
# [1] "agstudy"
gsub(newPunks("&#{"), "", x)
# [1] "a#gst{ud&y"

Bleah。我上床睡觉的时间......

答案 3 :(得分:3)

它在Perl中完全相同,[:punct:]是一个简单映射到的POSIX字符类:

[!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]

等效的Perl版本将是:

my $x = 'a#,g:?s!*$t/{u}\d\&y';
$x =~ s/[[:punct:]]//g;
print $x;

__END__
agstudy

答案 4 :(得分:3)

直截了当的方法是使用前瞻或后视来匹配相同的角色两次,一次确保它是一个punction,一次确保它不是“#”。

(?=[^#])[[:punct:]]

(?!#)[[:punct:]]
但是,前瞻和外观看起来有点贵。我们不是在每个位置都使用一个环视,而是在找到标点时使用一个更有效率。

[[:punct:]](?<!#)

当然,完全摆脱外观会更有效率。这可以通过双重否定来实现。

[^[:^punct:]#]

我没有用R测试这些,但它们至少应该与perl=TRUE一起使用。