Como posso excluir todas as linhas em inglês de um arquivo de texto?

11

Eu tenho este arquivo de texto:

714
01:11:22,267 --> 01:11:27,731
Auch wenn noch viele Generationen auf einen Wechsel hoffen,
Even if it takes many generations hoping for a change,

715
01:11:27,732 --> 01:11:31,920
werde ich mein Bestes geben
und hoffe, dass andere das gleiche tun.
I'm giving mine, I'm doing my best
hoping the other will do the same

716
01:11:31,921 --> 01:11:36,278
Wir haben eine harte Arbeit vor uns, 
um den Lauf der Dinge zu ändern. 
it's going to be hard work
for things to turn around.

717
01:11:36,879 --> 01:11:42,881
Wenn man die Zentren künstlicher Besamung, 
die Zuchtlaboratorien und die modernen Kuhställe besichtigt, 
When visiting artificial insemination centers,
the selection center, modern stables,
...

e gostaria de analisá-lo para que apenas as linhas não inglesas fiquem

Isso é possível?

Deele Ma
fonte
3
Você pode assumir com segurança que sempre haverá o mesmo número de linhas em cada idioma? Se houver duas linhas alemãs sempre haverá também duas linhas em inglês, etc.?
terdon

Respostas:

13

Existe uma maneira difícil e muito mais fácil. A maneira mais difícil é usar a análise de linguagem natural para dar uma probabilidade de que uma determinada linha esteja em inglês e descartar essas linhas.

A maneira mais fácil é pegar uma lista de palavras de parada em inglês e excluir linhas que contêm elementos dessa lista. Se você quisesse diminuir a chance de categorizar incorretamente uma linha, também poderia procurar a presença de palavras de parada em alemão nas linhas que você não consegue rejeitar para verificar se elas provavelmente são alemãs.

Aqui está um script muito rápido e sujo para usar a lista de palavras de parada vinculada para fazer a filtragem:

#!/usr/bin/python
english_stop = set()
with open('english-stop-words.txt') as estop:
    for line in estop:
        bar = line.find('|')
        if bar > -1:
            line = line[0:bar]
        line = line.strip()
        if line:
            english_stop.add(line)

with open('mixed-german.txt') as mixg:
    for line in mixg:
        for word in line.lower().split():
            if word in english_stop:
                break
        else:
            print line[:-1]

e a saída:

714
01:11:22,267 --> 01:11:27,731
Auch wenn noch viele Generationen auf einen Wechsel hoffen,

715
01:11:27,732 --> 01:11:31,920
werde ich mein Bestes geben
und hoffe, dass andere das gleiche tun.

716
01:11:31,921 --> 01:11:36,278
Wir haben eine harte Arbeit vor uns, 
um den Lauf der Dinge zu ändern. 

717
01:11:36,879 --> 01:11:42,881
Wenn man die Zentren künstlicher Besamung, 
die Zuchtlaboratorien und die modernen Kuhställe besichtigt, 

Uma versão um pouco mais completa deve ignorar várias pontuações, como ,.no apóstrofo inglês, 'quando dentro de uma palavra. É possível obter uma precisão ainda maior procurando pontos de código que nunca ocorrem em inglês (por exemplo «ßü), mas que são deixados como um exercício para o leitor.

msw
fonte
Abordagem muito agradável. Muito melhor do que o meu hack and slash abordagem 8-)
SLM
Danke (usando palavras de parada como diagnóstico de uma linguagem veio de uma parte da minha mente Eu não sabia que estava lá;)
msw
5

Na sua amostra, isso funcionaria:

awk -v RS= -F '\n' -v OFS='\n' '{NF=NF/2+1;printf "%s", $0 RT}'

Detalhes

  • RS=. Define o separador de registros . Um valor vazio é um caso especial que significa que um registro é um parágrafo (sequência de linhas delimitadas por linhas vazias).
  • -F '\n': define o separador de campos (os campos em cada registro são linhas).
  • OFS='\n': define o separador do campo de saída.

Para cada registro (parágrafo):

  • NF=1+NF/2(ou NF=2(as duas primeiras linhas) + (NF-2)/2(metade das linhas restantes)): altere o número de campos para excluir os ingleses.
  • printf "%s", $0 RT: imprime o registro seguido pelo terminador do registro (para restaurar a mesma quantidade de espaçamento entre parágrafos). Para ver o que o código acima está fazendo, é útil se você adicionar algumas instruções de impressão ao mix. Algo assim:

Isso assume finais de linha Unix. Se o arquivo estiver no formato MSDOS, como é comum nos arquivos de legenda, você precisará pré-processá-lo com d2uou dos2unix.

Stéphane Chazelas
fonte
Isso pressupõe que as linhas inglesas estejam sempre na 3ª ou na 4ª posição, certo?
slm
2
@slm. Não, essa metade das linhas é em inglês.
Stéphane Chazelas
Olhando um pouco mais, isso divide as linhas em registros. Em seguida, você procura dentro de cada registro o número de campos (NF). Uma NF é uma linha neste caso, certo? Ainda não entendi o que você está fazendo com a parte NF-=NF/2-1. Você está calculando, digamos, NF=4para o primeiro registro, 714. Então você obtém os valores NF=4e NF/2-1=1, em seguida, subtrai o valor 1de NFdeixar você com você 3? Em seguida, imprimindo os primeiros 3"campos" do registro, eliminando a quarta linha?
slm
3

A peça chave para esse tipo de abordagem é ter acesso a um bom banco de dados de palavras em inglês. Existe esse arquivo no meu sistema, /usr/share/dict/wordsque possui muitas palavras, mas outras fontes podem ser usadas.

Abordagem

Minha abordagem geral seria usar grepassim:

$ grep -vwf /usr/share/dict/words sample.txt

Onde está o seu exemplo de saída sample.txt.

Nos meus testes limitados, o tamanho do wordsdicionário pareceu atolar grep. Minha versão tem mais de 400k linhas. Então comecei a fazer algo assim para dividir um pouco:

$ head -10000 /usr/share/dict/words > ~/10000words

Execuções de amostra (10k)

O arquivo é executado usando as primeiras 10 mil palavras do "dicionário".

$ grep -vwf ~/10000words sample.txt
714
01:11:22,267 --> 01:11:27,731
Auch wenn noch viele Generationen auf einen Wechsel hoffen,

715
01:11:27,732 --> 01:11:31,920
werde ich mein Bestes geben
und hoffe, dass andere das gleiche tun.
I'm giving mine, I'm doing my best
hoping the other will do the same

716
01:11:31,921 --> 01:11:36,278
Wir haben eine harte Arbeit vor uns, 
um den Lauf der Dinge zu ändern. 
it's going to be hard work
for things to turn around.

717
01:11:36,879 --> 01:11:42,881
Wenn man die Zentren künstlicher Besamung, 
die Zuchtlaboratorien und die modernen Kuhställe besichtigt, 
When visiting artificial insemination centers,
the selection center, modern stables,

NOTA: Essa abordagem foi executada em ~ 1,5 segundos, no meu laptop i5.

Parece ser uma abordagem viável. No entanto, quando aumentei até 100k linhas, o processo demorou muito tempo a abortar antes de terminar, para que você pudesse dividir o wordsdicionário em vários arquivos.

NOTA: Quando eu recuei em 50k linhas, demorou 32 segundos.

Mergulho mais profundo (50 mil linhas)

Quando comecei a expandir o dicionário até 50k, deparei-me com o problema que tinha, sobreponho-me entre os idiomas.

$ grep -vwf ~/50000words sample.txt
714
01:11:22,267 --> 01:11:27,731

715
01:11:27,732 --> 01:11:31,920
werde ich mein Bestes geben
und hoffe, dass andere das gleiche tun.
hoping the other will do the same

716
01:11:31,921 --> 01:11:36,278
Wir haben eine harte Arbeit vor uns, 
um den Lauf der Dinge zu ändern. 

717
01:11:36,879 --> 01:11:42,881
Wenn man die Zentren künstlicher Besamung, 
die Zuchtlaboratorien und die modernen Kuhställe besichtigt, 
the selection center, modern stables,

Analisando o problema

Uma coisa boa dessa abordagem é que você pode remover -ve ver onde está a sobreposição:

$ grep -wf ~/50000words sample.txt
Auch wenn noch viele Generationen auf einen Wechsel hoffen,
Even if it takes many generations hoping for a change,
I'm giving mine, I'm doing my best
it's going to be hard work
for things to turn around.
When visiting artificial insemination centers,

aufAparentemente, a palavra está nos dois idiomas ... bem, pelo menos está no meu wordsarquivo, portanto, pode ser um pouco de tentativa e erro para refinar a lista de palavras, conforme necessário.

NOTA: Eu sabia que era a palavra aufporque a grepcoloria de vermelho, que não aparece na saída acima devido à natureza limitada do SE 8-).

$ grep auf ~/50000words 
auf
aufait
aufgabe
aufklarung
auftakt
baufrey
Beaufert
beaufet
beaufin
Beauford
Beaufort
beaufort
bechauffeur
slm
fonte
A palavra "auf" existe no idioma inglês? DEVE ser um bug no arquivo do word. Ele definitivamente não faz, a não menos autônomo (que deve ser a única maneira analisado para aqui) de qualquer maneira
SyntaxError
@ syntaxerror - como eu disse, está no arquivo da lista de palavras que eu estava usando. Estou analisando autônomo. Isso é o que grep -wf ...faz. Com um melhor suprimento de palavras, essa abordagem seria a mais direta. A outra solução (de Stephane) depende da estruturação dos dados e não os analisa de maneira contextual, a abordagem de msw parece ter melhores pernas para mim.
slm
Eu assumi que você estava analisando autônomo. Seja como for, eu afirmo que se a palavra "auf" é realmente parte de uma linguagem Inglês lista de palavras, eu quero ver a referência de dicionário, onde a sua existência está documentada. Muito provavelmente, você não encontrará um ... nunca. Mas como você pode ver, uma mera palavra pode criar confusão total em analisadores de todos os tipos.
Syntaxerror 5/09/13
@ syntaxerror - desculpe pela confusão, eu não estava discordando de você sobre "auf" ser uma palavra real, apenas que ela estava no arquivo de dicionário que eu estava usando. Aliás, verifiquei a linhagem desse arquivo e ele vem de um pacote no meu laptop Fedora 14 chamado words. Ele origina esse URL como o criador da lista de palavras que está usando: en.wikipedia.org/wiki/Moby_Project
slm
1

Parece um .srtarquivo. Se for, e se o número de linhas em inglês por legenda for sempre o mesmo que o número de linhas em alemão, você poderá usar:

awk 'BEGIN { RS="\r\n\r\n"; FS="\r\n"} {for (i=1;i<=(NF-2)/2+2; i++) print $i "\r"; print "\r"}' old.srt > new.srt

Onde old.srte new.srtseus arquivos de entrada e saída escolhidos.

wingedsubmariner
fonte