Como substituir/excluir uma nova linha (\n)?

Como substituir/excluir uma nova linha (\n)?

Só tive acesso busybox 1.27.2.

Atualmente estou processando um dicionário com mais de meio milhão de palavras e mais de 6.000 páginas (que foi extraído de um PDF com ghostscript e convertido em texto simples). Está em um 20MB .txtarquivo. Originalmente, cada palavra neste dicionário tem um guia ->para facilitar a busca por uma palavra.

O que estou tentando conseguir é torná-lo *nixamigável. Significa que se eu fizer isso: grep -e '->myfancyword' ./dictionary.txt.

Eu deveria obter como resultado:

->fancyword: This is a very fancy word. *Definition going on for more than 6 lines*

Isso é feito facilmente removendo todas as novas linhas \npara que cada palavra tenha toda a sua definição em uma linha muito longa, o que é bom. Posso substituir tudo \npor tr -d '\n'e, em seguida, obter a saída disso, sed 's/->/\n->/g'então terminarei com a definição de todas as palavras em uma única linha. Mesmo neste documento enorme, é algo feito em menos de 5 segundos.

Estou quase conseguindo o resultado que desejo, mas não é perfeito. Posso fazer isso grep -e '->word' ./dictionary.txte obter a definição completa da palavra. Mas não é cosmeticamente perfeito.

A razão pela qual não estou satisfeito com o resultado é porque o pdf original foi formatado para ser impresso em A4páginas, o que significa que quando há uma palavra longa ela é cortada. Assim:

por exemplo

->word: This is a defini-
tion.

Se eu processar o arquivo com o fluxo de trabalho anterior, obtive: ->word: This is a defini- tion.ao usar o grep na palavra desejada.

Até agora o que consegui realizar foi o seguinte:

  1. entrada
->firstword: This is a defini-
tion.
->secondword: This is a second defini-
tion.
  1. aplicado tr -d '\n' < ./dictionary.txt > ./dictionary2.txt

  2. a saída é:

->firstword: This is a defini- tion. ->secondword: This is a second defini- tion.
  1. corrido:sed -e 's/->/\n->/g' ./dictionary2.txt

  2. Terminando com:

saída

->firstword: This is a defini- tion.
->secondword: This is a second defini- tion.

Antes mesmo de fazer o segundo passo eu gostaria de remover o traço e a nova linha ( -\n) para "unir" todas as linhas cortadas.

Então, minha pergunta é: Como posso substituir/excluir a string específica que contém o traço -e o caractere de nova linha \n( -\n) no final da linha?

O que eu gosto de receber é:

saída (por favor, verifique se o traço e o espaço ( -) não estão mais presentes)

->firstword: This is a definition.
->secondword: This is a second definition.

Obrigado.

EDITAR:

Esta é uma página do arquivo PDF:


     ->abigeato. (Del lat. abigeatus). 1. m. Am. Hurto de ganado.
     ->abigeo. (Del lat. abigeus). 1. m. Am. Ladrón de ganado.
     ->abigotado, da. 1. adj. bigotudo.
     ->abinar. 1. tr. rur. y vulg. Binar la tierra.
     ->abintestato. (De ab intestato). 1. m. Der. Procedimiento judicial sobre herencia y
   adjudicación de bienes de quien muere sin testar.
     ->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par-
   tiendo de materia inerte. 2. f. Bioquím. síntesis abiótica.
     ->abiótico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida.  V. síntesis
   abiótica
     ->abipón, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca del
   Paraná. U. t. c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familia
   guaicurú hablada por los abipones.
     ->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, o en otros objetos.
     ->abisal. (Del lat. abyssus). 1. adj. abismal (|| perteneciente al abismo). 2. adj. Se dice de
   las zonas del mar profundo que se extienden más allá del talud continental, y corresponden a
   profundidades mayores de 2000 m. 3. adj. Perteneciente o relativo a tales zonas.
     ->abiselar. 1. tr. biselar.
     ->abisinio, nia. 1. adj. Natural de Abisinia, hoy Etiopía. U. t. c. s. 2. adj. Perteneciente o re-
   lativo a este país de África. 3. m. Lengua abisinia.  V. rito abisinio
     ->abismado, da. (Del part. de abismar). 1. adj. Dicho de una persona, de su expresión, de
   su gesto, etc.: Ensimismados, reconcentrados. 2. adj. Heráld. Dicho de una pieza del escudo:
   Puesta en el abismo.
     ->abismal (1).  (Del ár. hisp. almismár, y este del ár. clás. mismar). 1. m. Cada uno de los
   clavos con que se fijaba en el asta el hierro de la lanza.abismal2. 1. adj. Perteneciente o re-
   lativo al abismo. 2. adj. Muy profundo, insondable, incomprensible.
     ->abismar. 1. tr. Hundir en un abismo. U. t. c. prnl. 2. tr. Confundir, abatir. U. t. c. prnl. 3.
   prnl. Entregarse del todo a la contemplación, al dolor, etc. 4. prnl. Am. sorprenderse (|| con-
   moverse con algo imprevisto o raro).
     ->abismático, ca. 1. adj. abismal2.
     ->abismo. (Quizá del lat. vulg. *abyssimus, der. de abyssus, y este del gr. , sin fondo). 1.
   m. Profundidad grande, imponente y peligrosa, como la de los mares, la de un tajo, la de una
   sima, etc. U. t. en sent. fig. Se sumió en el abismo de la desesperación. 2. m. infierno (|| lugar
   de castigo eterno). 3. m. Cosa inmensa, insondable o incomprensible. 4. m. Diferencia
   grande entre cosas, personas, ideas, sentimientos, etc. 5. m. Heráld. Punto o parte central
   del escudo. 6. m. Nic. Maldad, perdición, ruina moral.

Isto é o que obtenho quando grep o texto normal após a extração ser concluída com ghostscript (processado apenas com dos2unix):


grep -e '->abiog' ./rae-dos2unix.txt
     ->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par-

É quando as etapas anteriores (1-4) são concluídas no texto, ao fazer o grep eu obtive:


grep -e '->abiog' ./rae-una-linea.txt
->abiogénesis. (De a-2, bio- y -génesis). 1. f. Producción hipotética de seres vivos par-   tiendo de materia inerte. 2. f. Bioquím. síntesis abiótica.     

Responder1

Isso é bastante fácil em Perl. A opção do perl -0diz para ele usar caracteres NUL em vez de novas linhas como separador de registros de entrada, portanto, a menos que haja caracteres NUL na entrada, ele tratará todo o arquivo de entrada como um registro. Mesmo que haja caracteres NUL, ele continuará processando os registros subsequentes, iguais ao primeiro.

Nota: isso significa que todo o arquivo de entrada deve caber na memória - em um sistema moderno com 16 GB ou mais de RAM, é improvável que isso seja um problema. Em um sistema mais antigo com memória RAM insuficiente, mas com troca suficiente, ele ainda funcionará, mas será muito mais lento.

$ cat input.txt
->firstword: This is a defini-
tion.
->secondword: This is a second defini-
tion.
$ perl -0 -p -e 's/-\s*\n//g' input.txt 
->firstword: This is a definition.
->secondword: This is a second definition.

Isso remove todas as sequências de um hífen seguido por zero ou mais caracteres de espaço em branco ( \s, veja abaixo), seguido por uma nova linha ( \n).

A \s*parte da regex existe para corresponder aos caracteres de espaço em branco finais quepoderestar no final de uma linha - na minha experiência, é muito comum que as linhas de texto tenham espaços em branco à direita (e são difíceis de detectar porque são caracteres não imprimíveis, ou seja, invisíveis). Alternativamente, use *(zero ou maisespaçocaracteres) ou [ \t]*(zero ou mais espaços ou tabulações) ou \h*(zero ou maishorizontalcaracteres de espaço em branco) em vez de \s*.

De man perlre:

O conjunto de caracteres considerados espaços em branco são aqueles que o Unicode chama de "Espaço em branco padrão", a saber:

U+0009 CHARACTER TABULATION
U+000A LINE FEED
U+000B LINE TABULATION
U+000C FORM FEED
U+000D CARRIAGE RETURN
U+0020 SPACE
U+0085 NEXT LINE
U+200E LEFT-TO-RIGHT MARK
U+200F RIGHT-TO-LEFT MARK
U+2028 LINE SEPARATOR
U+2029 PARAGRAPH SEPARATOR

NOTAS:

  1. Um -caractere não é o único caractere "hífen" ou "traço" possível que pode estar em uso. A Wikipedia tem páginas listando unicodeHífeneTraçopersonagens. Felizmente, perl tem bons recursos de manipulação de unicode, então o one-liner pode ser reescrito para usar \p{Dash}(or \p{Pd}) em vez de -corresponder a todos os caracteres da categoria traço:
$ perl -0 -p -e 's/\p{Dash}\h*\n//g' input.txt 
->firstword: This is a definition.
->secondword: This is a second definition.

No entanto, isso tratará os travessões da mesma forma que os hífens (portanto, removerá um travessão no final de uma linha, da mesma forma que faria com um hífen)... e não é incomum usar travessões em vez de parênteses . Você pode usar \p{Hyphen}em vez de, \p{Dash}se não se importar, uma mensagem de aviso sobre o "hífen" estar obsoleto. Ou você pode usar uma expressão de colchetes que contém apenas os pontos de código Unicode que você deseja tratar como hífens - por exemplo

    perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g' input.txt
  1. Eu recomendo não ter cada definição de palavra começando com ->. Isso tornará desnecessariamente estranho procurar por uma palavra com grep - a string de pesquisa terá que ser citada (por causa do >, que o shell usa para redirecionamento) e precedida por --(por causa do -, caso contrário, o grep tratará seu padrão de pesquisa como se você quisesse que fossem opções). por exemplo, você não será capaz de fazer apenas:

     grep ^firstword: dictionary.txt
    

    Em vez disso, você teria que fazer:

     grep -- '^->firstword:' dictionary.txt
    

Para um exemplo melhor, extraí o texto da sua imagem comtesseract-ocre execute-o por meio de uma versão do perl one-liner que também remove todas as novas linhas que não são seguidas por ->:

$ cat input2.txt 
->abigeato. (Del lat. abigeatus). 1. m. Am. Hurto de ganado.
->abigeo. (Del lat. abigeus). 1. m. Am. Ladrén de ganado.
->abigotado, da. 1. adj. bigotudo.
->abinar. 1. tr. rur. y vulg. Binar la tierra.
->abintestato. (De ab intestato). 1. m. Der. Procedimiento judicial sobre herencia y
adjudicacion de bienes de quien muere sin testar.
Eiiftiénesis. (De a-2, bio- y -génesis). 1. f. Produccién hipotética de seres vivos par-
tiendo de materia inerte. 2. f. Bioquim. sintesis abistica,
->abidtico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida. V. sintesis
abidtica
->abipon, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca del
Parana. U. t.c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familia
guaicurt hablada por los abipones.
->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, 0 en otros objetos.
->abisal. (Del lat. abyssus). 1. adj. abismal (|| perteneciente al abismo). 2. adj. Se dice de
las zonas del mar profundo que se extienden mas alla del talud continental, y corresponden a
$ perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g; s/\n+(?!->)//g' input2.txt
->abigeato. (Del lat. abigeatus). 1. m. Am. Hurto de ganado.
->abigeo. (Del lat. abigeus). 1. m. Am. Ladrén de ganado.
->abigotado, da. 1. adj. bigotudo.
->abinar. 1. tr. rur. y vulg. Binar la tierra.
->abintestato. (De ab intestato). 1. m. Der. Procedimiento judicial sobre herencia yadjudicacion de bienes de quien muere sin testar.Eiiftiénesis. (De a-2, bio- y -génesis). 1. f. Produccién hipotética de seres vivos partiendo de materia inerte. 2. f. Bioquim. sintesis abistica,
->abidtico, ca. 1. adj. Biol. Se dice del medio en que no es posible la vida. V. sintesisabidtica
->abipon, na. 1. adj. Se dice del individuo de un pueblo amerindio que habitaba cerca delParana. U. t.c. s. 2. adj. Perteneciente o relativo a los abipones. 3. m. Lengua de la familiaguaicurt hablada por los abipones.
->abisagrar. 1. tr. Clavar o fijar bisagras en las puertas y sus marcos, 0 en otros objetos.
->abisal. (Del lat. abyssus). 1. adj. abismal (|| perteneciente al abismo). 2. adj. Se dice delas zonas del mar profundo que se extienden mas alla del talud continental, y corresponden a

Ainda recomendo remover a ->sequência do arquivo de saída final. É um marcador útil durante o processamento do texto, mas problemático depois.


Um comentário de @zevzek resolve o problema “usa enormes quantidades de RAM”. Em vez de usar NUL como separador de registro de entrada, use ->como separador. Isso faz com que o script perl leia apenas uma definição de palavra por vez, em vez do arquivo inteiro de uma vez. Isso fará com que ele seja executado muito mais rápido com um arquivo de entrada muito grande, pois não usará toda a RAM disponível e fará com que o sistema seja trocado.

Outras alterações são necessárias no roteiro porque agora estamos tratando da sequência de caracteres que marca ocomeçode uma nova definição de palavra comofimda definição anterior. Especificamente, agora precisamos:

  • Altere a opção da linha de comando -p(sempre exibir o registro atual) para -n(exibir apenas o registro atual quando solicitado).
  • Remova os caracteres de fim de linha ( chomp()a função do Perl faz isso)
  • Verifique se o registro de entrada está vazio ou contém apenas espaços em branco porque agora haverá umimaginárioregistro vazio antes do primeiro registro real "abigeato" e não queremos imprimi-lo. (Por que de repente surge um registro vazio imaginário? Porque ->agora indica o fim de um registro, não o início de um novo. O ->in ->abigeatoé o separador entre o registro anterior (vazio) e o novo registro "abigeato")
  • imprima o registro modificado com "->" e uma nova linha.

Todos juntos, isso mudaria a linha final disto:

$ perl -0 -p -e 's/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g;
                 s/\n+(?!->)//g' input2.txt

para isso:

perl -n -e 'BEGIN { $/="->" };
            chomp;
            next if m/^\s*$/;
            s/[\N{U+002D}\N{U+00AD}\N{U+2010}\N{U+2011}]\h*\n//g;
            s/\n+//g;
            print "->$_\n"' input2.txt

A saída desta versão é igual à original, exceto que a linha de saída final termina com uma nova linha ( \n). O original não garantia isso, na verdade evitou removendo todas as novas linhas que não eram seguidas por ->. Este é um bônus grátis porque tecnicamente um arquivo é apenas um arquivo de texto em unix se cada linha terminar com \n.... na maioria das vezes, isso não importa (pelo menos, não com versões modernas de ferramentas padrão de processamento de texto) , mas alguns programas não lidam corretamente com a linha final de um "arquivo de texto" se ela não terminar com \n.

(Aliás, o original pode ser corrigido adicionando um bloco END para adicionar uma nova linha ao final da saída END { print "\n" }:)

$/é uma variável perl que define o separador de registro de entrada (veja man perlvarpara detalhes sobre variáveis ​​predefinidas/especiais/de controle do perl), semelhante à RSvariável em awk. Anteriormente, eu estava usando a opção do Perl -0para defini-lo como o caractere NUL (veja man perlrundetalhes sobre as opções de linha de comando do Perl).

BEGINas instruções acontecem uma vez no início de um script, antes e fora do while(<>) { ..... }loop implícito causado pelo uso de perl's -pou -nopções (que fazem o perl se comportar como um superpoderoso sedou sed -nrespectivamente). Da mesma forma, uma ENDinstrução acontece uma vez no final de um script, depois que todas as entradas foram lidas e processadas.

Responder2

Sugiro fazer isso em um único script usando o N;P;Dpadrão:

sed -e ':loop' -e '$!N;/\n->/!s/-*\n/ /;tloop' -e 'P;D'

Você faz um loop adicionando a linha 'N'ext e removendo as novas linhas com traço opcional ( s/-*\n/ /), até que a nova linha comece com ->.

informação relacionada