Alguns caracteres UTF-8 não são reconhecidos pelo grep ou sed

6

Tentando determinar todos os caracteres em um arquivo.

O arquivo sample consiste em:

a eɪ
abandon əˈbændən
ability əˈbɪləti
able ˈeɪbəl
able ˈeɪbl
abortion əˈbɔrʃən
abortion əˈbɔrʃn
about əˈbaʊt
above əˈbʌv
abroad əˈbrɔd

A localidade confirmada está correta:

$ echo $LANG

en_US.UTF-8

Um comando para pegar o segundo campo, dividido por caractere, e contar quantos:

$ cat sample | awk '{print $2}' | grep -o . | sort | uniq -c | sort -n

  1 a
  1 æ
  1 i
  1 v
  2 d
  2 t
  3 e
  3 l
  3 ɔ
  3 r
  4 n
  9 b
 11 ə
 17 ɪ

Onde está ʃ e ˈ ? Eles não estão combinando personagens ou nada de especial. Observe que outros caracteres UTF-8 são retirados: ɔ , ə e ɪ , por exemplo.

O BTW usando sed 's/\(.\)/\n/g' tem quase os mesmos resultados que grep -o . , exceto que adiciona uma linha para '\ n'.

Há algo que estou perdendo? O grep tem uma opção UTF-8 oculta?

Caso seja importante, estou usando Ubuntu 12.04.2 LTS .

    
por Yimin Rong 09.08.2013 / 17:10

2 respostas

3

O problema é que sort e uniq estão usando informações de agrupamento para a localidade. Desligar a localidade para os dois comandos funciona:

cat sample | awk '{print $2}' | grep -o . | LC_ALL=C sort | LC_ALL=C uniq -c | sort -n
      1 ʊ
      1 ʌ
      1 a
      1 æ
      1 i
      1 v
      2 ʃ
      2 d
      2 t
      3 e
      3 l
      3 ɔ
      3 r
      4 ɪ
      4 n
      9 ˈ
      9 b
     11 ə
    
por 09.08.2013 / 17:19
2

usando localidade 'C', no entanto, você perde o agrupamento humano (como fazer 'a' e 'A' equivalente).

se você precisar agrupar e manipular alguns caracteres não manipulados pelos dados de localidade da glibc; você pode criar sua própria localidade expandindo o agrupamento padrão.

Você pode copiar a definição da sua localidade atual (por exemplo, / usr / share / i18n / locales / en_US) para outro nome. Em seguida, edite-o e, na seção LC_COLLATE, tenha:

LC_COLLATE
copy "iso14651_t1"

reorder-after <e>
<U0259> <e>;<PCL>;<MIN>;IGNORE
reorder-after <s>
<U0283> <s>;<PCL>;<MIN>;IGNORE
reorder-end

END LC_COLLATE

compila com: localedef -f ./yourmodifiedfile -t UTF-8 ./someplace então você pode usar LC_ALL=./someplace em vez de LC_ALL=C

se você quiser usá-lo regularmente, coloque o diretório criado com as outras localidades padrão (geralmente / usr / share / locale ou / usr / lib / locale) e nomeie-o de maneira padrão (por exemplo, se ele for baseado em en_US, você poderia nomear "en_US @ IPA" por exemplo. Então você pode configurar suas localidades para ter LC_COLLATE = en_US @ IPA permanentemente (note que você não deve definir LC_ALL se você quiser definir individualmente algumas variáveis LC_ *)

Note também que U + 02C8 é um modificador, e por isso deve ser ignorado corretamente em collation. Mas se você precisar manipulá-lo como um caractere separado, você pode usá-lo (ascii aspas simples colocadas como iguais (para visualização de agrupamento) como U + 02C8, já que é assim que é digitado com frequência):

# defines a handy symbol, to group together similar chars
collating-symbol <'>

# define 
reorder-after <z>
<'>

reorder-after <e>
<U0259> <e>;<PCL>;<MIN>;IGNORE
reorder-after <s>
<U0283> <s>;<PCL>;<MIN>;IGNORE
reorder-after <'>
<U0027> <'>;<BAS>;IGNORE;IGNORE
<U02C8> <'>;<PCL>;IGNORE;IGNORE

reorder-end
As linhas

são: <unicode value> <1st level>;<2d level>;<3d level>;<4th level> os níveis são usados para classificá-los.

Eu acho (mas não tentei, eu deixei isso como um exercício :)) que se você apenas definir o último nível ele se comportará como quase ignorado para ordenação, mas ainda assim "diferente" do ponto de vista uniq (contanto que como a cadeia de todos os níveis é única, o personagem é único, eu acho).

Geralmente, o 1º nível é um símbolo de agrupamento, como para todas as letras e-like. O 2º nível é geralmente para o personagem base, existem vários outros símbolos para várias versões acentuadas e (peculiar?) É usado para "especial". O nível 3D é geralmente usado para diferenciar letras maiúsculas e minúsculas e coisas assim.

    
por 04.06.2014 / 16:20