Хотя решение от Jeroen выполняет свою работу, оно имеет недостаток, заключающийся в том, что оно не векторизовано и поэтому медленное, если применяется к большому количеству символов.Кроме того, он работает только с вектором символов длиной один и нужно использовать sapply
для более длинного вектора символов.
Чтобы продемонстрировать это, я сначала создаю большой вектор символов:
set.seed(123)
strings <- c("abcd", "& ' >", "&", "€ <")
many_strings <- sample(strings, 10000, replace = TRUE)
И примените функцию:
unescape_html <- function(str) {
xml2::xml_text(xml2::read_html(paste0("<x>", str, "</x>")))
}
system.time(res <- sapply(many_strings, unescape_html, USE.NAMES = FALSE))
## user system elapsed
## 2.327 0.000 2.326
head(res)
## [1] "& ' >" "€ <" "& ' >" "€ <" "€ <" "abcd"
Это намного быстрее, если все строки в символьном векторе объединить в одну большую строку, так что read_html()
и xml_text()
нужно толькоиспользоваться один раз.Затем строки можно легко снова разделить, используя strsplit()
:
unescape_html2 <- function(str){
html <- paste0("<x>", paste0(str, collapse = "#_|"), "</x>")
parsed <- xml2::xml_text(xml2::read_html(html))
strsplit(parsed, "#_|", fixed = TRUE)[[1]]
}
system.time(res2 <- unescape_html2(many_strings))
## user system elapsed
## 0.011 0.000 0.010
identical(res, res2)
## [1] TRUE
Конечно, вам нужно быть осторожным, чтобы строка, которую вы используете для объединения различных строк в str
("#_|"
вмой пример) нигде не появляется в str
.В противном случае вы введете ошибку, когда большая строка снова разделится в конце.