web-dev-qa-db-ja.com

引用符または括弧で囲まれていないテキストを削除するにはどうすればよいですか?

入力:

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

期待される出力:

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

ご覧のとおり、二重引用符と括弧を残したいと思います。

二重引用符または括弧の間にないものはすべて削除する必要があります。

5
TuxForLife

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()

出力:

"foo" (bar) (19) 
"foo"
  • すべての行が読み取られ、スペースで区切られた部分がpartsというリストに保存されます

  • 次に、reモジュールのsearch関数を使用して、"または(で始まり、"または)で終わる部分を見つけました。

実行方法:

たとえば、スクリプトを保存しますscript.py。これで、次の2つの方法で実行できます。

  • chmod u+x /path/to/script.pyで実行可能にし、/path/to/script.py /path/to/file.txtとして実行します。つまり、ファイルfile.txtを最初の引数として入力します。スクリプトとファイルの両方が同じディレクトリにある場合、そのディレクトリから./script.py file.txt

  • 実行可能にすることなく実行でき、python2 script.py file.txtとして実行できます。

編集した質問への回答:

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

出力:

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

新しいバージョン()または""の間にスペースを入れることができます):

以下のPerlコマンドを試してください(クレジット:@ steeldriver

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

初期バージョン()または""の間にスペースなし)

次のPerl onelinerを試すことができます。

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

別の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>
    

質問の編集版について:

assumeが存在する場合、opening文字ごとにclose文字があります:'('および'"'(仮定する必要があります) 、そうでない場合、ファイルが間違っているか、「ネストされた」括弧または引用符の場合、質問はより複雑なルールのセットに言及する必要があるため、以下のコードも同様に仕事をするはずです:

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

リスト内の文字をリストします:['(', ')', '"']、見つかった一致から2つのチャンクを作成し、各カップルの範囲にあるものを出力します。

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
Jacob Vlijm

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"


元のタスク

入力:

  1. 「foo」(バー)(19)

raboof "foo" raboof

期待される出力:

「foo」(バー)(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

出力:

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

あなた(またはこれを読んでいる同様の問題を持つ誰か)が改行を保存する必要がない場合、次のように動作します:

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

入力用

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

出力を生成します

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

改行が必要な場合は、いくつかのトリックを使用できます。この:

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

最初のsedは、すべての行の最後に$を追加します。 (これには任意の文字を使用できます。)2番目は上記とほぼ同じgrepですが、行末で$にも一致するため、すべての行末に一致します。 trは、改行をスペースに、ドルを改行に変換します。ただし、その前の出力にはtr$があり、その後に改行があったため、その後の出力には改行があり、その後にスペースがあります。最後のsedは、これらのスペースを取り除きます。

3
MvG

別のPerl

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

以下の簡単なpythonコードがこの仕事をします。

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

そして、正規表現のみを使用するPerlを介したもう1つ

$ 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は次のよ​​うになります。

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

これは、引用符付き文字列内のエスケープ文字も正しく処理します(たとえば、"Test \"string\""は1つの文字列として扱われます。

1
thomasrutter