web-dev-qa-db-fra.com

Comment puis-je supprimer du texte qui n'est PAS entre guillemets ou parenthèses?

Contribution:

19. "foo foo" (bar bar) (19) raboof
"foo foo" raboof

Production attendue:

"foo foo" (bar bar) (19)
"foo foo"

Comme vous pouvez le constater, j'aimerais conserver les guillemets et les parenthèses.

Tout ce qui ne se trouve pas entre guillemets ou parenthèses doit être supprimé.

5
TuxForLife

Utiliser python:

#!/usr/bin/env python2
import re, sys
with open(sys.argv[1]) as f:
    for line in f:
        parts = line.split()
        for i in parts:
            if re.search(r'^[("].*[)"]$', i):
                print i,
        print '\n'.lstrip()

Sortie:

"foo" (bar) (19) 
"foo"
  • Chaque ligne est lue et les parties séparées par des espaces sont enregistrées dans une liste appelée parts

  • Ensuite, en utilisant la fonction re du module search du module, nous avons trouvé les parties commençant par " ou ( et se terminant par " ou ).

Comment exécuter:

Enregistrez le script sous le nom, par exemple. script.py. Maintenant, vous pouvez le lancer de deux manières:

  • Rendez-le exécutable par chmod u+x /path/to/script.py et exécutez-le en tant que /path/to/script.py /path/to/file.txt c'est-à-dire entrez le fichier file.txt en tant que premier argument. Si le script et le fichier se trouvent dans le même répertoire, à partir de ce répertoire ./script.py file.txt

  • Vous pouvez l'exécuter sans le rendre exécutable, exécutez-le en tant que python2 script.py file.txt.

Réponse à la question modifiée:

#!/usr/bin/env python2
import re, sys
with open(sys.argv[1]) as f:
    for line in f:
        print ''.join(re.findall(r'(?:(?<=\s)["(].*[")](?=\s|$)|(?<=^)["(].*[")](?=\s|$))', line))

Sortie:

"foo foo" (bar bar) (19)
"foo foo"
10
heemayl

Nouvelle version (espaces autorisés entre () ou ""):

Essayez la commande Perl ci-dessous (crédits: @ steeldriver )

Perl -ne 'printf "%s\n", join(" " , $_ =~ /["(].*?[)"]/g)'

Version initiale (aucun espace entre () ou "")

Vous pouvez essayer ce qui suit Perl oneliner:

$ Perl -ne '@a=split(/\s+/, $_); for (@a) {print "$_ " if /[("].*?[)"]/ };print"\n"'  file
5
Sylvain Pineau

Une autre option python:

#!/usr/bin/env python3
import sys
match = lambda ch1, ch2, w: all([w.startswith(ch1), w.endswith(ch2)])

for l in open(sys.argv[1]).read().splitlines():
    matches = [w for w in l.split() if any([match("(", ")", w), match('"', '"', w)])]
    print((" ").join(matches))
  • Copiez le script dans un fichier vide, enregistrez-le sous le nom filter.py

  • Exécutez-le avec la commande:

    python3 /path/to/filter.py <file>
    

Sur la version modifiée de la question:

Si nous supposons il y a un caractère fermant sur chaque ouvrant caractère: '(' et '"' (nous devrions supposer que , car sinon le fichier serait incorrect ou la question devrait mentionner un ensemble de règles plus complexe dans le cas de parenthèses ou de guillemets "imbriqués"), le code ci-dessous devrait également faire le travail:

#!/usr/bin/env python3
import sys
chunks = lambda l: [l[i:i + 2] for i in range(0, len(l), 2)]

for l in open(sys.argv[1]).read().splitlines():
    words = chunks([i for i in range(len(l)) if l[i] in ['(', ')', '"']])
    print((" ").join([l[w[0]:w[1]+1] for w in words]))

Il répertorie les caractères de la liste: ['(', ')', '"'], crée des fragments de deux correspondances trouvées et imprime ce qui se trouve dans la plage de chaque couple:

19. "foo" (bar bar) (blub blub blub blub) (19) raboof
"foo" raboof

affichera alors:

"foo" (bar bar) (blub blub blub blub) (19)
"foo"

L'utilisation est exactement comme le premier script.

Plusieurs "déclencheurs" peuvent être facilement ajoutés en ajoutant les deux côtés (caractère de début et de fin de la chaîne ou de la section à "conserver") dans la liste:

['(', ')', '"']

dans la ligne:

words = chunks([i for i in range(len(l)) if l[i] in ['(', ')', '"']])
4
Jacob Vlijm

Comme script Perl:

$filename=$ARGV[0];
if (open(my $fh, '<:encoding(UTF-8)', $filename)) {
  while (my $match = <$fh>) {
    while ($match =~ /((\(.*?[^)]\))|(".*?"))/g) {
      print "$1 ";
    }
    print "\n"
  }
}

Ou comme Perl one-liner:

Perl -ne 'while (/((\(.*?[^)]\))|(".*?"))/g) {print "$1 ";} print "\n"' file

Sortie

"foo foo" (bar bar) (19) 
"foo foo"


C'était le tâche originale :

Entrée:

  1. "foo" (bar) (19)

raboof "foo" raboof

Résultat attendu:

"foo" (bar) (19)

"foo"

Utiliser Perl:

Perl -pe '@elements=( split (/\s/) ); 
    for $element (@elements) {
        if ($element!~/^"|\(/ and $element!~/"|\($/) {
            s/$element//
        }
        s/^\s+//;
        s/\s+$/\n/
    };' file

ou comme one-liner:

Perl -pe '@elements=( split (/\s/) ); for $element (@elements) { if ($element!~/^"|\(/ and $element!~/"|\($/) { s/$element// } s/^\s+//; s/\s+$/\n/ };' file

Sortie:

"foo" (bar) (19)
"foo"
3
A.B.

Si vous (ou une autre personne ayant un problème similaire qui lit ceci) n'avez pas besoin de conserver les nouvelles lignes, les opérations suivantes fonctionneraient:

grep -Eo '"[^"]*"|\([^)]*\)'

Pour l'entrée

19. "foo foo" (bar bar) (19) raboof
"foo foo" raboof

il produit une sortie

"foo foo"
(bar bar)
(19)
"foo foo"

Si vous avez besoin de nouvelles lignes, vous pouvez utiliser certaines astuces, par exemple. cette:

sed 's/$/\$/' \
| grep -Eo '"[^"]*"|\([^)]*\)|\$$' \
| tr '\n$' ' \n' \
| sed 's/^ //'

Le premier sed ajoute un $ à la fin de chaque ligne. (Vous pouvez utiliser n'importe quel caractère pour cela.) Le second est presque identique à grep comme ci-dessus, mais correspond également à $ à la fin d'une ligne. Il correspond donc à chaque fin de ligne. Le tr transforme les nouvelles lignes en espaces et les dollars en nouvelles lignes. Mais puisque la sortie précédente tr avait $ suivie de nouvelle ligne, la sortie suivante comportera une nouvelle ligne suivie d'un espace. La version finale sed supprime ces espaces.

3
MvG

Un autre Perl:

$ Perl -nle 'print join " ", $_ =~ /".*?"|\(.*?\)/g' file
"foo foo" (bar bar) (19)
"foo foo"
2
cuonglm

Ci-dessous, le simple code python fera ce travail.

import re
with open('file') as f:
    reg = re.compile(r'"[^"]*"|\([^)]*\)')
    for line in f:
        print(' '.join(reg.findall(line)))

Et un autre par Perl qui utilise seulement regex,

$ Perl -pe 's/(?:"[^"]*"|\([^)]*\))(*SKIP)(*F)|\S//g;s/^\h+|\h+$|(\h)+/\1/g' file
"foo foo" (bar bar) (19)
"foo foo"
2
Avinash Raj

PHP serait:

if (preg_match_all('/"(?:[^"\\\\]+|\\\\.)+"|\\([^)]+\\)/', $input, $matches)) {
  echo implode(' ', $matches[0]);
}

Cela gère également correctement les caractères échappés dans les chaînes entre guillemets (par exemple, "Test \"string\"" est traité comme une chaîne.

1
thomasrutter