R/regex with stringi/ICU:为什么'+'被认为是非[:punct:]字符?

scr*_*Owl 15 regex string r icu stringi

我正在尝试从字符串向量中删除非字母字符.我认为[:punct:]分组会覆盖它,但它似乎忽略了+.这属于另一组角色吗?

library(stringi)
string1 <- c(
"this is a test"
,"this, is also a test"
,"this is the final. test"
,"this is the final + test!"
)

string1 <- stri_replace_all_regex(string1, '[:punct:]', ' ')
string1 <- stri_replace_all_regex(string1, '\\+', ' ')
Run Code Online (Sandbox Code Playgroud)

hwn*_*wnd 18

POSIX字符类需要包含在字符类中,正确的形式是 [[:punct:]].不要将POSIX术语"字符类"与通常称为正则表达式字符类的内容混淆.

ASCII范围内的此POSIX命名类与所有非控件,非字母数字,非空格字符匹配.

ascii <- rawToChar(as.raw(0:127), multiple=T)
paste(ascii[grepl('[[:punct:]]', ascii)], collapse="")
# [1] "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
Run Code Online (Sandbox Code Playgroud)

虽然如果a locale 有效,它可能会改变 [[:punct:]] ... 的行为

R Documentation ?regex指出以下内容:某些命名的字符类是预定义的.他们的解释取决于地区(见区域); 解释是POSIX语言环境的解释.

punct的Open Group LC_TYPE定义说:

定义要分类为标点字符的字符.

在POSIX 语言环境中,<space>不应包括alpha,digit或cntrl类中的任何字符.

在区域设置定义文件中,不会为关键字upper,lower,alpha,digit,cntrl,xdigit或指定的关键字指定字符<space>.


但是,stringi包似乎依赖于ICU,而语言环境是ICU中的一个基本概念.

使用stringi包,我建议使用Unicode属性\p{P}\p{S}.

  • \p{P}匹配任何类型的标点字符.也就是说,它缺少POSIX类punct包含的九个字符.这是因为Unicode将POSIX认为标点符号分为两类,标点符号符号.这是\p{S}到位的地方......

    stri_replace_all_regex(string1, '[\\p{P}\\p{S}]', ' ')
    # [1] "this is a test"            "this  is also a test"     
    # [3] "this is the final  test"   "this is the final   test "
    
    Run Code Online (Sandbox Code Playgroud)
  • gsub从基地R 回退,处理这个问题非常好.

    gsub('[[:punct:]]', ' ', string1)
    # [1] "this is a test"            "this  is also a test"     
    # [3] "this is the final  test"   "this is the final   test "
    
    Run Code Online (Sandbox Code Playgroud)

  • 我从未见过适合使用stringi或stringr的另一个例子.普通的R正则表达式已经非常干净且"规则".包装它只会增加错误容量. (7认同)
  • @BondedDust,实际上stringis的主要优点是速度.它不是一个包装器,而是完全重写的.与stringr不同,就我所知,它基本上是一个包装器 (7认同)
  • 我出于速度原因使用它,这是一个50MM行的文件.当事情有效时,stringi比stringr快约100倍. (3认同)
  • 对.我的印象不正确.看起来它还提供了模式和替换参数的矢量化,但如果没有更好的文档,它对我没什么用处. (2认同)

gag*_*ews 16

在类似POSIX的正则表达式引擎中,punct代表与ispunct()分类函数对应的字符类(man 3 ispunct在类UNIX系统上查看).根据ISO/IEC 9899:1990(ISO C90),该ispunct()功能测试任何打印字符,除了空格或字符为 isalnum()真.但是,在POSIX设置中,哪些字符属于哪个类的详细信息取决于当前的区域设置.因此punct这里的类不会导致可移植代码, 有关详细信息,请参阅有关C/POSIX迁移ICU用户指南.

另一方面,stringi依赖的ICU库完全符合Unicode标准,它自己定义了一些charclasses - 但是定义良好且始终是可移植的.

特别是,根据Unicode标准,PLUS SIGN(U+002B)属于Symbol, Math (Sm)类别(而不是Puctuation Mark(P)).

library("stringi")
ascii <- stri_enc_fromutf32(1:127)
stri_extract_all_regex(ascii, "[[:punct:]]")[[1]]
##  [1] "!"  "\"" "#"  "%"  "&"  "'"  "("  ")"  "*"  ","  "-"  "."  "/"  ":"  ";"  "?"  "@"  "["  "\\" "]"  "_"  "{"  "}" 
stri_extract_all_regex(ascii, "[[:symbol:]]")[[1]]
## [1] "$" "+" "<" "=" ">" "^" "`" "|" "~"
Run Code Online (Sandbox Code Playgroud)

所以在这里,你应该宁愿使用字符集和[[:punct:][:symbol:]],[[:punct:]+]或者甚至更好[\\p{P}\\p{S}][\\p{P}+].

有关可用字符类的详细信息,请查看 ?"stringi-search-charclass".特别是,关于UnicodeSet的ICU用户指南Unicode标准附件#44:Unicode字符数据库 可能是您感兴趣的.HTH