web-dev-qa-db-fra.com

Comment rechercher dans un fichier des lignes ne contenant que des caractères ASCII, puis y donner suite?

J'ai un fichier texte qui ressemble à ceci:

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

Notez qu'au milieu, il y a deux lignes, English words only et Also English words only, l'une après l'autre.

Ce que je dois faire, c'est prendre ces deux lignes et les combiner en une seule ligne séparée par un /, comme ceci:

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

J'ai constaté que je pouvais rechercher des lignes avec ASCII caractères avec l'expression régulière suivante, [[:ascii:]], et pour les caractères non-ASCII avec [^[:ascii:]]. Cependant, j'ai un peu de mal à utiliser les expressions régulières pour trouver des instances de ne correspondant pas à une condition, car ce sur quoi j'ai besoin de chercher sont des lignes sans caractères non-ASCII.

J'ai trouvé cette question à propos de "correspondance inverse" , mais, les réponses sont au-delà de moi.

Ensuite, bien sûr, c’est un autre problème que de faire correspondre les lignes en fonction de leurs relations. Puis-je faire correspondre ces lignes lorsqu'elles se succèdent? Je ne suis même pas sûr que c'est possible.

Est-il possible de rechercher toutes les lignes sans caractères non-ASCII, puis de les combiner à l'aide de LibreOffice, de Gedit ou de la ligne de commande?

Notez que le fichier contient des milliers de lignes, et je ne suis pas sûr non plus, mais il est possible qu'il puisse y avoir des occurrences de lignes en anglais uniquement sont en groupes de 3 ou 4.

6
Questioner

Il semble que vous puissiez utiliser sed pour effectuer ce travail, même s'il ne connaît pas la classe de caractères [[:ascii:]]. Au lieu de cela, nous pouvons spécifier tous les ASCII caractères avec une plage de séquences d'échappement[\d0-\d127], tant que nous utilisons le C ou POSIX lieux.

Voici une commande qui devrait être fiable:

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

Remarques

  • LC_ALL=C Utilisez C paramètres régionaux uniquement pour cette commande (sinon, vous obtiendrez une erreur).
  • -r Utilisez une expression rationnelle étendue pour rendre la commande plus lisible (nous avons besoin de moins de barres obliques inverses) (GNU sed reconnaît également -E avec le même sens).
  • :a Label - La boucle commence ici
  • ; Séparer les commandes, comme dans le shell
  • N Lit la ligne suivante dans l'espace de répétition pour pouvoir remplacer \n
  • s|old|new| Remplacez old par new
  • ^([\d0-\d127])\n([\d0-\d127]+)$ - faites correspondre deux lignes avec uniquement ASCII et capturez la première ligne dans \1 et la deuxième ligne dans \2. ^ est le début de la ligne, \n est une nouvelle ligne et $ est la fin de la ligne, donc ^line 1\nline 2$ teste l'ensemble de line 1 et line 2.
  • \1 / \2 Les première et deuxième lignes, séparées par  /  au lieu d'une nouvelle ligne.
  • ta - Si la dernière commande de recherche-remplacement a réussi, exécutez à nouveau la boucle. Cela nous permet de traiter toutes les lignes du fichier, en gérant toutes les instances où il y a plus de deux lignes entièrement ASCII ensemble.

Un grand merci à Eliah Kagan pour me montrant comment utiliser les séquences d'échappement pour faire correspondre les caractères ASCII .

4
Zanna

Si vous voulez des lignes entières composées uniquement de ASCII caractères, vous devez ancrer votre modèle au début et à la fin de la ligne, par exemple. avec grep

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

Certains outils fournissent un indicateur de ligne complète tel que -x ou --line-regexp de 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 $.

vous permettant d'utiliser:

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

La correspondance multiligne ajoute une autre couche de complexité, car de nombreux utilitaires de traitement de texte en ligne de commande courants sont basés sur des lignes. Vous pouvez forcer grep à Slurp d'un fichier entier à l'aide de l'indicateur -Z. Toutefois, il existe des outils tels que pcregrep ou Perl lui-même sont probablement plus appropriés à ce stade.

Le problème suivant est de savoir comment interpréter les concepts "début de ligne" et "fin de ligne" dans le contexte d'une correspondance multiligne. Certains outils fournissent des indicateurs pour cela, comme décrit dans Didacticiel Regex: Ancres : Perl en fait partie, qui fournit un modificateur /m. Vous devez toujours slurp le fichier en désactivant le séparateur d'enregistrement par défaut (fait ici en utilisant -0777); par exemple

$ 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 日本語
日本語のみ
4
steeldriver