Как удалить текст, который НЕ в кавычках или круглых скобках?

Вход:

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

Ожидаемый результат:

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

Как вы можете видеть, я хотел бы сохранить двойные кавычки и круглые скобки.

] Все, что не находится между двойными кавычками или круглыми скобками, должно быть удалено.

1
задан 26 June 2015 в 00:26

7 ответов

Новая версия (пробелы между () или ""):

Попробуйте выполнить команду perl (кредиты: @steeldriver)

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

Новая версия (без пробелов между () или "")

Вы можете попробовать следующее perl oneliner:

$ perl -ne '@a=split(/\s+/, $_); for (@a) {print "$_ " if /[("].*?[)"]/ };print"\n"'  file
5
ответ дан 23 May 2018 в 20:47
  • 1
    Короче, и он работает +1;) – A.B. 1 May 2015 в 22:22
  • 2
    Он изменил задачу. Это несправедливо. – A.B. 1 May 2015 в 22:36
  • 3
    Это отлично поработало для первоначального вопроса, который был связан с одним словом внутри круглых скобок и котировок. Однако после дальнейшего расследования я обнаружил, что он не работает с несколькими словами в боковых кавычках / круглых скобках. Мои искренние извинения, я не имел в виду никакого вреда – TuxForLife 1 May 2015 в 22:51
  • 4
    @ user264974: Нет проблем, рад, что вы нашли свой ответ. – Sylvain Pineau 2 May 2015 в 00:03
  • 5
    @SylvainPineau Я думаю, что трюк для второго случая не , чтобы разбить входные данные перед поиском совпадений регулярных выражений, например. [F1] – steeldriver 2 May 2015 в 01:02

Еще одна опция 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))
Скопируйте сценарий в пустой файл, сохраните скрипт как filter.py Запустите его с помощью команды:
python3 /path/to/filter.py <file>

На отредактированная версия вопроса:

Если мы предположим, что на каждом начальном символе есть символ закрытия: '(' и '"' (мы должны предположить, что, поскольку иначе либо файл был бы неправильным, либо вопрос следует упомянуть более сложный набор правил в случае «вложенных» круглых скобок или кавычек), следующий код должен также выполнить задание:

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

В нем перечислены символы в списке: ['(', ')', '"'], делает куски двух из найденных совпадений и печатает то, что находится в диапазоне каждой пары:

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

выдает:

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

Использование в точности как и первый скрипт.

Более или менее «триггеры» можно легко добавить, добавив в список обе стороны (начальный и конечный символ строки или раздела «сохранить»):

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

в строке:

words = chunks([i for i in range(len(l)) if l[i] in ['(', ')', '"']])
4
ответ дан 23 May 2018 в 20:47
  • 1
    Я заметил, что сценарий не работает, как я ожидал, если текст между кавычками и круглыми скобками содержит пробел, но это моя ошибка, потому что я не конкретный. Я редактировал мой вопрос – TuxForLife 1 May 2015 в 22:10
  • 2
    @ user264974 Нет проблем, но вы даете нам новую задачу :) – Jacob Vlijm 1 May 2015 в 22:12
  • 3
    Отличное редактирование, спасибо, теперь он работает с тем, что я намеревался использовать для него с включенными пробелами. Я сохранил его как второй вариант для heemayl's. Мне нравится, как мы можем получать разные результаты с помощью разных методов! – TuxForLife 2 May 2015 в 21:11

Если вы (или кто-то другой с аналогичной проблемой, кто читает это), не должны сохранять символы новой строки, будет работать следующее:

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

Для ввода

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

он дает выход

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

Если вам нужны новые строки, вы можете использовать некоторые трюки, например this:

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

Первый sed добавляет $ в конец каждой строки. (Вы можете использовать любой символ для этого.) Второй почти тот же grep, что и выше, но теперь также совпадает с $ в конце строки, поэтому он соответствует каждому концу строки. [F9] превращает новые строки в пробелы и доллары в новые строки. Но так как на выходе до tr было $, за которым следует новая строка, на выходе после будет новая строка, за которой следует пробел. Финал sed избавляется от этих пространств.

3
ответ дан 23 May 2018 в 20:47

Как скрипт perl:

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

Или как perl однострочный:

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

Выход

"foo foo" (bar bar) (19) 
"foo foo"
[ ! d4]

Это была оригинальная задача:

Вход: «foo» (bar) (19) raboof «foo» raboof Ожидаемый результат: «foo» (bar ) (19) «foo»

Используя perl:

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

или как однострочный:

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

Выход [ ! d3]

"foo" (bar) (19)
"foo"
3
ответ дан 23 May 2018 в 20:47

Другой perl:

$ perl -nle 'print join " ", $_ =~ /".*?"|\(.*?\)/g' file
"foo foo" (bar bar) (19)
"foo foo"
2
ответ дан 23 May 2018 в 20:47

Ниже простого кода python будет выполняться это задание.

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

И еще один через Perl, который использует только регулярное выражение,

$ perl -pe 's/(?:"[^"]*"|\([^)]*\))(*SKIP)(*F)|\S//g;s/^\h+|\h+$|(\h)+/\1/g' file
"foo foo" (bar bar) (19)
"foo foo"
2
ответ дан 23 May 2018 в 20:47

PHP будет:

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

Это также корректно обрабатывает экранированные символы внутри цитируемых строк (например, "Test \"string\"" рассматривается как одна строка.

1
ответ дан 23 May 2018 в 20:47

Другие вопросы по тегам:

Похожие вопросы: