Comment puis-je supprimer toutes les lignes anglaises d'un fichier texte?


11

J'ai ce fichier texte:

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,
...

et je voudrais l'analyser de sorte que seules les lignes non anglais restent

Est-ce possible?


3
Pouvez-vous supposer en toute sécurité qu'il y aura toujours le même nombre de lignes dans chaque langue? S'il y a deux lignes allemandes, y aura-t-il toujours aussi deux lignes anglaises, etc.?
terdon

Réponses:


13

Il y a une voie difficile et une voie beaucoup plus facile. La méthode la plus difficile consiste à utiliser l'analyse en langage naturel pour donner une probabilité qu'une ligne donnée soit en anglais et supprimer ces lignes.

Le moyen le plus simple consiste à prendre une liste de mots vides en anglais et à supprimer les lignes contenant des éléments de cette liste. Si vous souhaitez réduire les risques de catégorisation erronée d'une ligne, vous pouvez également rechercher la présence de mots vides allemands dans les lignes que vous ne parvenez pas à rejeter pour vérifier qu'ils sont probablement allemands.

Voici un script très rapide et sale pour utiliser la liste de mots vides liés pour effectuer le filtrage:

#!/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]

et la sortie:

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, 

Une version légèrement plus complète devrait ignorer diverses ponctuations comme ,.mais pas l'apostrophe anglaise 'dans un mot. Une précision encore plus grande pourrait être obtenue en recherchant des points de code qui ne se produisent jamais en anglais (par exemple «ßü), mais cela reste un exercice pour le lecteur.


Très belle approche. Beaucoup mieux que mon approche hack and slash 8-)
slm

Danke (utiliser des mots vides comme diagnostic d'une langue est venu d'une partie de mon esprit que je ne connaissais pas;)
msw

5

Sur votre échantillon, cela fonctionnerait:

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

Détails

  • RS=. Définit le séparateur d'enregistrement . Une valeur vide est un cas particulier qui signifie qu'un enregistrement est un paragraphe (séquence de lignes délimitées par des lignes vides).
  • -F '\n': définit le séparateur de champs (les champs de chaque enregistrement sont des lignes).
  • OFS='\n': définit le séparateur de champ de sortie.

Pour chaque enregistrement (paragraphe):

  • NF=1+NF/2(ou NF=2(les 2 premières lignes) + (NF-2)/2(la moitié des lignes restantes)): modifiez le nombre de champs pour exclure les champs anglais.
  • printf "%s", $0 RT: imprime l' enregistrement suivi de la terminaison d'enregistrement (pour restaurer la même quantité d'espacement entre les paragraphes). Pour voir ce que fait le code ci-dessus, il est utile si vous ajoutez des instructions d'impression dans le mélange. Quelque chose comme ça:

Cela suppose des fins de ligne Unix. Si le fichier est au format MSDOS comme cela est courant avec les fichiers de sous-titres, vous devez le prétraiter avec d2uou dos2unix.


Cela suppose que les lignes anglaises sont toujours en 3e ou 4e position, non?
slm

2
@slm. Non, la moitié des lignes sont en anglais.
Stéphane Chazelas

En regardant un peu plus, cela brise les lignes en enregistrements. Vous recherchez ensuite dans chaque enregistrement le nombre de champs (NF). Une NF est une ligne dans ce cas, non? Je ne comprends toujours pas ce que tu fais avec le NF-=NF/2-1bit. Êtes-vous en train de calculer, disons, NF=4pour le premier enregistrement, 714. Donc, vous obtenez les valeurs NF=4et NF/2-1=1, puis soustrayez le 1de NFvous laissant avec 3? Ensuite, l'impression des premiers 3"champs" de l'enregistrement, d'où la suppression de la 4ème ligne?
slm

3

L'élément clé de ce type d'approche est d'avoir accès à une bonne base de données de mots anglais. Il y a ce fichier sur mon système, /usr/share/dict/wordsqui contient beaucoup de mots, mais d'autres sources pourraient être utilisées à la place.

Approche

Mon approche générale serait d'utiliser grepcomme ceci:

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

Où se trouve votre exemple de sortie sample.txt.

Dans mes tests limités, la taille du wordsdictionnaire semblait greps'enliser. Ma version contient 400k + lignes. J'ai donc commencé à faire quelque chose comme ça pour le casser un peu:

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

Exemples de courses (10k)

Exécutez votre fichier en utilisant les premiers 10k mots du "dictionnaire".

$ 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,

REMARQUE: cette approche a fonctionné en environ 1,5 seconde sur mon ordinateur portable i5.

Cela semble être une approche viable. Quand je l'ai fait passer à 100 000 lignes, cela a commencé à prendre du temps, je l'ai avorté avant qu'il ne soit terminé, afin que vous puissiez diviser le wordsdictionnaire en plusieurs fichiers.

REMARQUE: lorsque je l'ai reculé sur 50 000 lignes, cela a pris 32 secondes.

Plonger plus profondément (50k lignes)

Quand j'ai commencé à étendre le dictionnaire jusqu'à 50k, je suis tombé sur le problème dont j'avais peur, le chevauchement entre les langues.

$ 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,

Analyser le problème

Une bonne chose avec cette approche est que vous pouvez supprimer le -vet voir où se trouve le chevauchement:

$ 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,

Le mot aufest apparemment dans les deux langues ... enfin au moins, il est dans mon wordsdossier, donc cela pourrait être un peu une approche par essais et erreurs pour affiner la liste de mots selon les besoins.

REMARQUE: je savais que c'était le mot aufparce qu'il était grepcoloré en rouge, cela n'apparaît pas dans la sortie ci-dessus en raison de la nature limitée de SE 8-).

$ grep auf ~/50000words 
auf
aufait
aufgabe
aufklarung
auftakt
baufrey
Beaufert
beaufet
beaufin
Beauford
Beaufort
beaufort
bechauffeur

Le mot "auf" existe-t-il en anglais? Cela DOIT être un bug dans le fichier Word. Ce n'est certainement pas le cas, du moins pas de façon autonome (ce qui devrait être la seule façon d'analyser ici) de toute façon
syntaxerror

@syntaxerror - comme je l'ai dit, c'est dans le fichier de liste de mots que j'utilisais. J'analyse de façon autonome. C'est ce que grep -wf ...ça fait. Avec une meilleure offre de mots, cette approche serait la plus directe. L'autre solution (celle de Stéphane) dépend des données qui sont structurées et ne les considère pas de manière contextuelle, l'approche de msw semble cependant avoir de meilleures jambes.
slm

Je suppose que vous étiez analysez autonome. Quoiqu'il en soit, j'affirme que si le mot « auf » fait vraiment partie d'une langue anglaise liste de mots, je veux voir la référence dictionnaire où son existence est documentée. Très probablement, vous n'en trouverez pas ... jamais. Mais comme vous pouvez le voir, un simple mot peut créer une confusion totale dans les analyseurs de toutes sortes.
erreur de syntaxe

@syntaxerror - désolé pour la confusion, je n'étais pas en désaccord avec vous sur le fait que "auf" soit un vrai mot, juste qu'il se trouve dans le fichier de dictionnaire que j'utilisais. Soit dit en passant, j'ai revérifié la lignée de ce fichier et il provient d'un package sur mon ordinateur portable Fedora 14 appelé mots. Il source cette URL en tant qu'origine des listes de mots qu'il utilise: en.wikipedia.org/wiki/Moby_Project
slm

1

Cela ressemble à un .srtfichier. Si c'est le cas, et si le nombre de lignes anglaises par sous-titre est toujours le même que le nombre de lignes allemandes, alors vous pouvez utiliser:

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

old.srtet où new.srtsont vos fichiers d'entrée et de sortie choisis.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.