西里尔字母的正则表达式问题

Reg Expressions Issues with Cyrillic letters

我过去在正则表达式和西里尔字母方面遇到过问题,所以我想知道我是否做错了什么?

这里有两个可重现的例子:

示例 1 - 前瞻和后视断言问题:

latin <- "city New York, Manhattan\n1st Avenue"
cyrilic <- "град Ню Йорк, Манхатън\n1во Авеню"

stringr::str_extract(latin, pattern = "(?<=city New York, )[\w\s]+(?=\n)")
#returns: Manhattan

stringr::str_extract(cyrilic, pattern = "(?<=град Ню Йорк, )[\w\s]+(?=\n)")
stringr::str_extract(cyrilic, pattern = "(?<=град Ню Йорк, ).+(?=\n)")
#both return: NA

示例 2 - grep 的问题 ignore.case = TRUE:

randomWord <- "Човек"

grep(pattern = "човек", x = randomWord, ignore.case = T)
#returns: integer(0)

关于如何编写正则表达式以使其在西里尔字母中工作的任何想法?

我的默认文本编码是 UTF-8,这是我的会话信息:

> sessionInfo()
R version 3.3.3 (2017-03-06)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)

locale:
[1] LC_COLLATE=Bulgarian_Bulgaria.1251  LC_CTYPE=Bulgarian_Bulgaria.1251   
[3] LC_MONETARY=Bulgarian_Bulgaria.1251 LC_NUMERIC=C                       
[5] LC_TIME=Bulgarian_Bulgaria.1251 

我不确定为什么在这种情况下 str_extract returns NA,因为看起来正则表达式是有效的。

但是 str_locatestr_detect 似乎按预期工作:

stringr::str_detect(cyrilic, "(?<=град Ню Йорк, )[\w\s]+(?=\n)")
#returns TRUE
stringr::str_locate(cyrilic, "(?<=град Ню Йорк, )[\w\s]+(?=\n)")
#returns the start and end positions for Манхатън

您的问题的解决方法是结合使用 substr()str_locate:

substr(cyrilic, 
   stringr::str_locate(cyrilic, "(?<=град Ню Йорк, )[\w\s]+(?=\n)")[1], 
   stringr::str_locate(cyrilic, "(?<=град Ню Йорк, )[\w\s]+(?=\n)")[2]
)
#returns 'Манхатън'

问题可能出在 ICU 如何处理从 stringr str_extract 接收到的模式:看起来生成的后视模式不再是已知宽度。或者,str_extract.

存在其他错误

在这种情况下,使用模式长度没有问题的 str_match 会更安全:

> str_match(cyrilic, pattern = "град Ню Йорк,\s*([\w\s]+)\n")[,2]
[1] "Манхатън"

只要访问正确的组,在这里,它是结果列表中的第二项。

至于您在 grep 中使用的 TRE 正则表达式,我还在不同环境中观察到各种问题。在我的 Windows 7 机器上,您的代码 returns 1。但是,使用文字 Unicode 字母的 TRE 正则表达式可能会失败,最佳做法是使用 PCRE 正则表达式。为了使其完全识别 Unicode,不要忘记在模式开头添加 (*UCP) PCRE 动词,以便 \w\d 等可以匹配所有 Unicode 字符。这里,没有必要and

> randomWord <- "Човек"
> grep(pattern = "човек", x = randomWord, ignore.case = T, perl=TRUE)
[1] 1

同样有效。