R/regex with stringi/ICU: почему символ "+" считается символом non - [: punct:]?
Я пытаюсь удалить не-алфавитные символы из вектора строк. Я думал, что группа [:punct:]
будет охватывать ее, но, похоже, она игнорирует +
. Это относится к другой группе символов?
library(stringi)
string1 <- c(
"this is a test"
,"this, is also a test"
,"this is the final. test"
,"this is the final + test!"
)
string1 <- stri_replace_all_regex(string1, '[:punct:]', ' ')
string1 <- stri_replace_all_regex(string1, '\\+', ' ')
Ответы
Ответ 1
Символьные классы POSIX должны быть обернуты внутри класса символов, правильная форма будет [[:punct:]]
. Не путайте термин "класс символов" POSIX с тем, что обычно называется классом символов регулярных выражений.
Этот класс с именем POSIX в диапазоне ASCII соответствует всем неконтролируемым, не буквенно-цифровым, а не пробелам символам.
ascii <- rawToChar(as.raw(0:127), multiple=T)
paste(ascii[grepl('[[:punct:]]', ascii)], collapse="")
# [1] "!\"#$%&'()*+,-./:;<=>[email protected][\\]^_`{|}~"
Хотя, если действует locale
, это может изменить поведение [[:punct:]]
...
R Документация ?regex
указывает следующее: Определенные классы символов предопределены. Их интерпретация зависит от локали (см. locales); интерпретация - это язык языкового стандарта POSIX.
Открытая группа Определение LC_TYPE для punct говорит:
Определите символы, которые будут классифицированы как знаки пунктуации.
В POSIX локали не включаются ни <space>
, ни любые символы в классах alpha, digit или cntrl.
В файле определения локали не указывается ни один символ, указанный для ключевых слов: верхний, нижний, альфа, цифра, cntrl, xdigit или как <space>
.
Однако пакет stringi, по-видимому, зависит от ICU, а локаль - фундаментальная концепция в ICU.
Используя пакет stringi, я рекомендую использовать Unicode Properties \p{P}
и \p{S}
.
-
\p{P}
соответствует любому знаку пунктуации. То есть отсутствует девять символов, которые включает в себя класс POSIX. Это связано с тем, что Unicode разделяет то, что POSIX считает препинанием на две категории, Знаки пунктуации и Символы. Это где \p{S}
вступает в действие...
stri_replace_all_regex(string1, '[\\p{P}\\p{S}]', ' ')
# [1] "this is a test" "this is also a test"
# [3] "this is the final test" "this is the final test "
-
Или отбросьте на gsub
из базы R, которая обрабатывает это очень хорошо.
gsub('[[:punct:]]', ' ', string1)
# [1] "this is a test" "this is also a test"
# [3] "this is the final test" "this is the final test "
Ответ 2
В POSIX-подобных системах регулярных выражений punct
означает
класс символов, соответствующий классификации ispunct()
(проверьте man 3 ispunct
на UNIX-подобных системах).
Согласно ISO/IEC 9899: 1990 (ISO C90), функциональные тесты ispunct()
для любого символа печати, кроме пробела или символа, для которого
isalnum()
истинно. Однако, в настройках POSIX, детали того, что
символы принадлежат классу в зависимости от текущей локали.
Таким образом, класс punct
здесь не приведет к переносу кода,
см. руководство пользователя ICU по миграции C/POSIX.
для более подробной информации.
С другой стороны, библиотека ICU, на которой полагается stringi,
и который полностью соответствует стандарту Unicode,
определяет некоторые из charclasses в своей собственной, но четко определенной
и всегда в переносном режиме.
В частности, согласно стандарту Unicode,
PLUS SIGN
(U+002B
) имеет значение Symbol, Math
(Sm
) (и не является Puctuation Mark
(P
)).
library("stringi")
ascii <- stri_enc_fromutf32(1:127)
stri_extract_all_regex(ascii, "[[:punct:]]")[[1]]
## [1] "!" "\"" "#" "%" "&" "'" "(" ")" "*" "," "-" "." "/" ":" ";" "?" "@" "[" "\\" "]" "_" "{" "}"
stri_extract_all_regex(ascii, "[[:symbol:]]")[[1]]
## [1] "$" "+" "<" "=" ">" "^" "`" "|" "~"
Итак, здесь вы должны использовать такие наборы символов
как [[:punct:][:symbol:]]
, [[:punct:]+]
,
или даже лучше [\\p{P}\\p{S}]
или
[\\p{P}+]
.
Подробнее о доступных классах символов см.
?"stringi-search-charclass"
.
В частности, Руководство пользователя ICU по UnicodeSet
и Стандартное приложение Unicode № 44: база данных символов Юникода
возможно, вашего интереса. НТН