某些使用从在线提取的字符串的代码不符合我的预期,您可以通过运行以下代码重现该问题:
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)
如果x和y是相同的,如何能够将这些给出了不同的输出?
?identical :
测试两个对象完全相等的安全可靠的方法
编辑:
这是一个可观察到的差异:
Encoding(x) # "UTF-8"
Encoding(y) # "latin1"
Run Code Online (Sandbox Code Playgroud)
我跑R version 3.5.0的Windows
为了克服这个问题,您需要确保您的模式是 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)
如果您查看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)