字符串是相同的(使用`base :: identical`),但与`grepl` /`gsub`的行为不同

Moo*_*per 9 regex encoding r

相关:将大写单词转换为标题大小写

某些使用从在线提取的字符串的代码不符合我的预期,您可以通过运行以下代码重现该问题:

library(xml2)
library(magrittr)
x <- xml2::read_html("https://poesie.webnet.fr/lesgrandsclassiques/Authors/B") %>%
  gsub("^.*?<span>(Pierre-Jean de BÉRANGER)</span>.*$","\\1",.)
x # [1] "Pierre-Jean de BÉRANGER"
Run Code Online (Sandbox Code Playgroud)

此字符串与"Pierre-Jean de BÉRANGER"从页面源复制/粘贴相同,但以下行为对我来说非常令人不安:

y <- "Pierre-Jean de BÉRANGER"
x == y  # TRUE
identical(x, y) # TRUE
gsub("\\b([A-Z])(\\w+)\\b", "\\1\\L\\2", x, perl = TRUE) # [1] "Pierre-Jean de BÉRANGER"
gsub("\\b([A-Z])(\\w+)\\b", "\\1\\L\\2", y, perl = TRUE) # [1] "Pierre-Jean de Béranger"
grepl("\\bB\\w+", x, perl = TRUE) # FALSE
grepl("\\bB\\w+", y, perl = TRUE) # TRUE
grepl("\\bB\\w", x, perl = TRUE)  # TRUE
grepl("\\bB\\w", y, perl = TRUE)  # TRUE
Run Code Online (Sandbox Code Playgroud)

如果xy是相同的,如何能够将这些给出了不同的输出?

?identical :

测试两个对象完全相等的安全可靠的方法


编辑:

这是一个可观察到的差异:

Encoding(x) # "UTF-8"
Encoding(y) # "latin1"
Run Code Online (Sandbox Code Playgroud)

我跑R version 3.5.0Windows

Wik*_*żew 5

为了克服这个问题,您需要确保您的模式是 Unicode 感知的,以便\w可以匹配所有 Unicode 字母和数字,并且\b可以匹配 Unicode 单词边界。这可以通过使用 PCRE 动词来实现(*UCP)

gsub("(*UCP)\\b([A-Z])(\\w+)\\b", "\\1\\L\\2", x, perl = TRUE)
      ^^^^^^
Run Code Online (Sandbox Code Playgroud)

要使其完全 Unicode 使用\p{Lu}而不是[A-Z]

gsub("(*UCP)\\b(\\p{Lu})(\\w+)\\b", "\\1\\L\\2", x, perl = TRUE)
Run Code Online (Sandbox Code Playgroud)

此外,如果您不想匹配数字和_,您可以替换\w\p{L}(任何字母):

gsub("(*UCP)\\b(\\p{Lu})(\\p{L}+)\\b", "\\1\\L\\2", x, perl = TRUE)
Run Code Online (Sandbox Code Playgroud)


MrF*_*ick 2

如果您查看Sametime() 函数的源代码,您会发现当它传递一个CHARSXP值(字符向量)时,它会调用内部辅助函数Seql()。该函数在进行比较之前将字符串值转换为 UTF 。因此,identical并不检查编码是否必须相同,只是检查编码中嵌入的值是否相同。

在完美的世界中,除了进行比较时可以忽略的所有其他属性之外,该identical()函数还应该有一个选项。ignore.encoding=

但从理论上讲,字符串实际上应该以相同的方式运行。所以我想你可以在这里责怪“perl”版本的 regexpr 引擎没有正确处理编码。基本的正则表达式引擎似乎没有这个问题

grepl("B\\w+", x)
# [1] TRUE
grepl("B\\w+", y)
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)