Como eu procuro por linhas em um arquivo que contém apenas caracteres ASCII e, em seguida, atuo neles?

6

Eu tenho um arquivo de texto com esta aparência:

English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ
English words only
Also English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ

Observe que, no meio, há duas linhas, English words only e Also English words only , uma logo após a outra.

O que eu preciso fazer é pegar essas duas linhas e combinar em uma linha separada por um / , assim:

English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ
English words only / Also English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ

Descobri que posso procurar linhas com caracteres ASCII com a seguinte expressão regular, [[:ascii:]] e para não-ASCII com [^[:ascii:]] . No entanto, estou tendo um pequeno problema ao usar expressões regulares para localizar instâncias de não correspondentes a uma condição, pois o que preciso pesquisar são linhas sem caracteres não-ASCII.

Eu encontrei essa pergunta sobre "correspondência inversa" , mas as respostas estão além de mim.

Então, é claro, é outro problema para combinar as linhas com base no relacionamento entre elas. Posso combinar essas linhas quando elas são uma após a outra? Eu nem tenho certeza se isso é possível.

Existe uma maneira de procurar por todas as linhas sem caracteres não-ASCII e depois combiná-las usando o LibreOffice, o Gedit ou a linha de comando?

Note que o arquivo tem milhares de linhas, e também não tenho certeza, mas pode ser possível que possa haver ocorrências de apenas linhas em inglês que estejam em grupos de 3 ou 4.

    
por Questioner 26.04.2018 / 16:41

2 respostas

4

Parece que você pode usar sed para fazer este trabalho, mesmo que não saiba sobre a classe de caracter [[:ascii:]] . Em vez disso, podemos especificar todos os caracteres ASCII com um intervalo de seqüências de escape [\d0-\d127] , desde que usemos as C ou POSIX locales.

Aqui está um comando que deve ser confiável:

LC_ALL=C sed -r ':a;N;s|^([\d0-\d127]+)\n([\d0-\d127]+)$| / |;ta' file

Notas

  • LC_ALL=C Use as configurações C locale apenas para este comando (caso contrário, você receberá um erro)
  • -r Use o regex estendido para tornar o comando mais legível (precisamos de menos barras invertidas) (o GNU sed também reconhece -E com o mesmo significado).
  • :a Label - o loop começa aqui
  • ; Separa os comandos, como no shell
  • N Leia a próxima linha no espaço de padrão, para que possamos substituir \n
  • s|old|new| Substituir old por new
  • ^([\d0-\d127])\n([\d0-\d127]+)$ - combina duas linhas apenas com ASCII e captura a primeira linha em e a segunda linha em . ^ é o início da linha, \n é uma nova linha e $ é o fim da linha, por isso ^line 1\nline 2$ testa a totalidade de line 1 e line 2 .
  • / A primeira e segunda linhas, separadas por  /  em vez de uma nova linha.
  • ta - Se o último comando de pesquisa e substituição tiver êxito, execute o loop novamente. Isso nos permite processar todas as linhas do arquivo, lidando com todas as instâncias em que houver mais de duas linhas all-ASCII juntas.

Muito obrigado a Eliah Kagan por mostrando-me como usar sequências de escape para corresponder aos caracteres ASCII .

    
por Zanna 26.04.2018 / 18:29
4

Se você quiser linhas inteiras consistindo apenas em caracteres ASCII, será necessário ancorar seu padrão no início e no fim da linha, por exemplo, com grep

$ grep -P '^[[:ascii:]]*$' file
English words only
English words only
English words only
Also English words only
English words only

Algumas ferramentas fornecem um sinalizador de linha inteira, como -x ou --line-regexp :

do grep
   -x, --line-regexp
          Select  only  those  matches  that exactly match the whole line.
          For a regular expression pattern, this  is  like  parenthesizing
          the pattern and then surrounding it with ^ and $.

permitindo que você use:

$ grep -Px '[[:ascii:]]*' file
English words only
English words only
English words only
Also English words only
English words only
A correspondência de

Multiline adiciona uma outra camada de complexidade, já que muitos dos utilitários comuns de processamento de texto de linha de comando são baseados em linha. Você pode forçar o grep a fazer slurp de um arquivo inteiro usando o -Z flag, mas existem ferramentas como pcregrep ou perl em si são provavelmente mais apropriadas nesse ponto.

A questão seguinte que você precisa resolver é como interpretar os conceitos "início da linha" e "fim da linha" no contexto de uma correspondência multilinha. Algumas ferramentas fornecem sinalizadores para isso, conforme descrito em Tutorial Regex: Âncoras : perl é um desses, que fornece um modificador /m . Você ainda precisa fazer o slurp do arquivo desabilitando o separador de registro padrão (feito aqui usando -0777 ); por exemplo

$ perl -0777 -pe 's{^([[:ascii:]]+)\n([[:ascii:]]+)$}{$1 / $2}mg' file
English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ
English words only / Also English words only
English and 日本語
日本語のみ
English words only
English and 日本語
日本語のみ
    
por steeldriver 26.04.2018 / 16:48