A cadeia ilegível corresponde a uma expressão regular constituída apenas por caracteres legíveis

1

Considere os comandos abaixo:

STR="Êîðîëü è Øóò"; # Invalid (Russian in unrecognized encoding)
#STR="а б в г д"; # Valid (Russian)
#STR="a b c d e"; # Valid (English)
#STR="a b c d e а б в г д"; # Valid (English and Russian)



# The regex consists of latin and Russian characters
REGEX="^[a-zA-Zа-яА-Я ]+$"

if ! [[ "$STR" =~ $REGEX ]] ; then
  echo "Unreadable string: ""$STR";
fi


$ echo $LC_ALL
ru_RU.UTF-8

Eu esperava "Unreadable string: Êîðîëü è Øóò" como saída, mas não havia nada.

    
por ka3ak 18.08.2017 / 13:33

1 resposta

4

O que varia como A-Z ou а-я correspondência não é especificado por POSIX diferente da localidade POSIX (para A-Z , não а-я obviamente).

Somente na localidade POSIX você pode obter a garantia de que [A-Z] corresponde apenas aos caracteres ABCDEFGHIJKLMNOPQRSTUVWXYZ .

Em outras localidades, o comportamento varia entre as implementações. Alguns podem corresponder a qualquer elemento de intercalação (podem ser caracteres ou sequências de caracteres) que classifica após A e antes de Z (pode incluir ch , x ou Á , mas não Ź por exemplo) , ou eles poderiam corresponder em caracteres cujo ponto de código é maior que o de A e menor que o de Z no conjunto de caracteres do locale, ou eles poderiam usar os dados de agrupamento de localidade de uma maneira diferente ... Observe também que nem todos concordam com a ordem das letras para qualquer script (como o latim ou o cirílico nesse caso), então você terá diferentes comportamentos para diferentes localidades que incluam esses scripts no conjunto de caracteres (mesmo que seja o mesmo conjunto de caracteres)) .

Se você quiser corresponder qualquer caractere alfabético em qualquer script, use [[:alpha:]] , se quiser corresponder intervalos de caracteres com base no ponto de código em UTF-8, tente usar o C.UTF-8 locale disponível em muitos sistemas.

Se você quiser corresponder em qualquer letra do alfabeto latino, use perl ou pcre \p{Latin} (inclui é , Ê ...). Em zsh :

set -o rematchpcre
[[ $x =~ '^(\p{Latin}|\p{Cyrillic})$' ]]

Você pode restringir a letra latina àquelas encontradas somente em ASCII com (ainda com zsh e ainda com rematchpcre ):

[[ $x =~ '^((?=[[:ascii:]])\p{Latin}|\p{Cyrillic})$' ]]

embora em vigor com rematchpcre , ^([a-zA-Z]|\p{Cyrillic})$ teria o mesmo efeito, pois os intervalos em PCRE e em zsh são baseados no valor codepoint e essas letras têm a garantia de ter os mesmos pontos de código e estar nesse idioma. seqüência de alfabeto com todas as localidades em sistemas POSIX baseados em ASCII e baseados em EBCDIC, pelo menos.

Ou você pode listar os caracteres explicitamente se quiser apenas um subconjunto, para evitar toda ambigüidade:

[[ $x =~ ^[ABC...XYZabc...xyzабв...эюя]$ ]]

Você sempre pode armazená-los em variáveis como:

ascii_upper=ABC...XYZ
ascii_lower=abc...xzy
cyr_upper=...
[[ $x =~ ^[$ascii_upper$ascii_lower$cyr_upper...]$ ]]
    
por 18.08.2017 / 14:45