对十六进制字符使用 `grepl` 并使用 `stringi::stri_escape_unicode()` 转义 unicode 非 ASCII 字符

问题描述 投票:0回答:1

老问题

我有一个 R 包,其中有一个大学名称列表,我想将其与用户输入相匹配。名称列表包含特殊字符,这会在 R CMD 检查中生成警告:

checking data for non-ASCII characters (855ms)
     Warning: found non-ASCII strings

现在,我正在将这些非 ASCII unicode 字符转换为符合 ASCII 的转义版本,以使用

stringi::stri_escape_unicode()
消除此警告。然而,现在我在其他函数中所需的 grepl 似乎没有按预期工作:

用户提供带有重音符号的文本(例如“é”),我将其与我的数据库进行匹配。但它似乎没有正确检测字符串:

a <- stringi::stri_escape_unicode("é")

a == "é"
#> [1] FALSE

a == "\\é"
#> [1] FALSE

grepl("é", a)
#> [1] FALSE

创建于 2023-09-03,使用 reprex v2.0.2

注:后续this


编辑:

大学名单

大学列表在此处创建:https://github.com/rempsyc/pubmedDashboard/blob/master/data-raw/universities.R

但现在我意识到(感谢您在评论中指出这一方面),当我对大学名称和附属地址进行比较时,我使用

easyPubMed
的输出,它实际上似乎使用了不同的编码(尽管默认编码)应该使用UTF8)。

在 RStudio 查看器中,将鼠标悬停在附属地址上时,它看起来像这样,例如“Département de Psychologie, Université du Québec à Montréal, Montréal”。

然而,它似乎实际上是这样编码的(编辑:即使在 stackoverflow 上,符号也被正确渲染,所以我必须将它们作为代码):

"D&#xe9;partement de Psychologie, Universit&#xe9; du Qu&#xe9;bec &#xe0; Montr&#xe9;al, Montr&#xe9;al"

我意识到这可能就是比较不起作用的原因:

"é" == "&#xe9;"
#> [1] FALSE

创建于 2023-09-03,使用 reprex v2.0.2

我的错误是假设我在 RStudio 中使用鼠标悬停时看到的是真实的角色,而在幕后却是不同的东西。

十六进制字符

据我所知,这种编码形式对应于 Unicode 十六进制字符代码。我需要的可能是

stringi
中的另一个函数,用于从 Unicode 十六进制字符代码转换为常规编码。

这是

easyPubMed
包提供的地址从属关系的表示:

library(easyPubMed)
dami_query_string <- "Dualistic Model of Passion [Text Word] AND ('2023/01/01' [Date - Publication] : '2023/12/31' [Date - Publication])"
dami_on_pubmed <- get_pubmed_ids(dami_query_string)
pubmed_data <- fetch_pubmed_data(dami_on_pubmed)
dami_abstracts_list <- articles_to_list(pubmed_data)
article_to_df(dami_abstracts_list[[5]])$address[1]
#> [1] "Laboratoire de Recherche sur le Comportement Social, D&#xe9"

但是由于

article_to_df
内部的错误,完整的地址没有显示。为此,我们必须使用
pubmedDashboard
的版本:

# remotes::install_github("rempsyc/pubmedDashboard")
library(pubmedDashboard)
article_to_df2(dami_abstracts_list[[5]])$address[1]
#> [1] "Laboratoire de Recherche sur le Comportement Social, D&#xe9;partement de Psychologie, Universit&#xe9; du Qu&#xe9;bec &#xe0; Montr&#xe9;al, Montr&#xe9;al, QC H3C 3P8, Canada."

创建于 2023-09-03,使用 reprex v2.0.2

检测到的编码是什么?

stringi::stri_enc_detect("&#xe9;")
#> [[1]]
#>   Encoding Language Confidence
#> 1    UTF-8                0.15
#> 2 UTF-16BE                0.10
#> 3 UTF-16LE                0.10

创建于 2023-09-03,使用 reprex v2.0.2

转换十六进制字符

这个网站转换似乎可以解决问题,但我无法用

stringi
...

做同样的事情

代表:

stringi::stri_encode("&#xe9;", from = "UTF8", to = "ASCII")
#> [1] "&#xe9;"

stringi::stri_encode("&#xe9;", from = "UTF16", to = "ASCII")
#> Warning in stringi::stri_encode("&#xe9;", from = "UTF16", to = "ASCII"): the
#> Unicode code point \U00002623 cannot be converted to destination encoding
#> Warning in stringi::stri_encode("&#xe9;", from = "UTF16", to = "ASCII"): the
#> Unicode code point \U00007865 cannot be converted to destination encoding
#> Warning in stringi::stri_encode("&#xe9;", from = "UTF16", to = "ASCII"): the
#> Unicode code point \U0000393b cannot be converted to destination encoding
#> [1] "\032\032\032"

stringi::stri_encode("&#xe9;", from = "Hex", to = "ASCII")
#> Error in stringi::stri_encode("&#xe9;", from = "Hex", to = "ASCII"): The requested ICU resource file cannot be found. (U_FILE_ACCESS_ERROR)

创建于 2023-09-03,使用 reprex v2.0.2

stringi::stri_unescape_unicode("&#xe9;")
#> [1] "&#xe9;"

创建于 2023-09-03,使用 reprex v2.0.2

更改编码
easyPubMed

我在想,也许如果我可以直接从 easyPubMed 更改编码,那会让我的生活更轻松。根据包文档这是可能的:

请注意,我们包含一个参数(即编码)来强制对检索到的记录进行编码。这里,我们推荐“UTF8”。但是,您可以选择不同的编码(取决于本地平台)。例如,这里我们指定编码=“ASCII”。

但似乎我无法正确执行十六进制:

library(easyPubMed)
dami_query_string <- "Dualistic Model of Passion [Text Word] AND ('2023/01/01' [Date - Publication] : '2023/12/31' [Date - Publication])"
dami_on_pubmed <- get_pubmed_ids(dami_query_string)
pubmed_data <- fetch_pubmed_data(dami_on_pubmed)

dami_abstracts_list <- articles_to_list(pubmed_data, encoding = "ASCII")
article_to_df(dami_abstracts_list[[5]])$address[1]
#> [1] "Laboratoire de Recherche sur le Comportement Social, D&#xe9"

dami_abstracts_list <- articles_to_list(pubmed_data, encoding = "UTF8")
article_to_df(dami_abstracts_list[[5]])$address[1]
#> [1] "Laboratoire de Recherche sur le Comportement Social, D&#xe9"

dami_abstracts_list <- articles_to_list(pubmed_data, encoding = "UTF16")
article_to_df(dami_abstracts_list[[5]])$address[1]
#> [1] "Laboratoire de Recherche sur le Comportement Social, D&#xe9"

dami_abstracts_list <- articles_to_list(pubmed_data, encoding = "latin")
article_to_df(dami_abstracts_list[[5]])$address[1]
#> [1] "Laboratoire de Recherche sur le Comportement Social, D&#xe9"

dami_abstracts_list <- articles_to_list(pubmed_data, encoding = "unicode")
article_to_df(dami_abstracts_list[[5]])$address[1]
#> [1] "Laboratoire de Recherche sur le Comportement Social, D&#xe9"

dami_abstracts_list <- articles_to_list(pubmed_data, encoding = "hex")
article_to_df(dami_abstracts_list[[5]])$address[1]
#> [1] "Laboratoire de Recherche sur le Comportement Social, D&#xe9"

创建于 2023-09-03,使用 reprex v2.0.2

r escaping non-ascii-characters grepl
1个回答
0
投票

第一步,我们必须定义一个新函数来将十六进制字符转换为常规文本:

convert_hex_to_char <- function(hex_string) {
  # Extract all hex codes from the string using stringi::stri_extract_all_regex
  hex_codes <- stringi::stri_extract_all_regex(hex_string, "&#x[0-9a-fA-F]+;")[[1]]
  
  # Convert hex codes to characters
  chars <- lapply(hex_codes, function(hex_code) {
    int_val <- strtoi(gsub("&#x(.*);", "\\1", hex_code), base=16)
    char <- intToUtf8(int_val)
    return(char)
  })
  chars <- as.character(chars)
  
  # Replace hex codes with characters in the original string
  for (i in seq_along(hex_codes)) {
    hex_string <- sub(hex_codes[i], chars[i], hex_string)
  }
  
  return(hex_string)
}

# Test the function
sentence <- "D&#xe9;partement de Psychologie, Universit&#xe9; du Qu&#xe9;bec &#xe0; Montr&#xe9;al, Montr&#xe9;al"
converted_sentence <- convert_hex_to_char(sentence)
converted_sentence
#> [1] "Département de Psychologie, Université du Québec à Montréal, Montréal"

但是,将十六进制字符转换为常规文本是不够的,因为即使这样也无法匹配转义的 unicode。因此,我们需要对大学名称进行转义(在下面的示例中进行了简化):

pattern <- stringi::stri_unescape_unicode(stringi::stri_escape_unicode("Université"))
grepl(pattern, converted_sentence)
#> [1] TRUE

注意:感谢 ChatGPT 提供此功能。几乎可以肯定有一个现有的函数或包可以做到这一点,我将接受具有此类解决方案的另一个答案。

创建于 2023-09-03,使用 reprex v2.0.2

© www.soinside.com 2019 - 2024. All rights reserved.