次のような1行のファイルがあります。パスツールビンしかし、はるかに長いです。
私の目標は、example1:start with <a
end with </a>
example2:start with PZ
end withの文字列部分のみをフィルタリングすることですs16
。したがって、各場合、テキストはHTMLエンティティに依存せず、一致の間に保持されます。
FreeBSD
HTMLエンティティに依存する解決策はすでにあります。
- 複数行で美しく飾る
tidy -i -m -w 160 -ashtml -utf8 ~/file
- 文字列が含まれていない場合は行を削除する
sed -i '' '/\<\/a\>/!d' ~/file
ところで、HTMLエンティティに依存せずに直接フィルタを実行しようとしています。現時点では、一致の正確な先頭のみを取得できますが、フィルタリングしている文字列の内容がどれほど長いかわからないため、一致の終わりを正確に取得することはできません。予期しない結果の再現手順をご覧ください。
予期しない結果を再現する手順
wget -O ~/file https://pastebin.com/raw/xbti369J
grep -E -o ".{0,0}PZ.{0,46}" ~/file
固定長を要求したため、行が正しくありません。
PZ</td><td class="s15">€ 1.20</td><td class="s16
PZ</td><td class="s15"></td><td class="s16">A</t
目的は、長さに関係なく、次のように結果的な線パターンを得ることです。
PZ</td><td class="s15">€ 1.20</td><td class="s16
PZ</td><td class="s15"></td><td class="s16
答え1
のようなXMLパーサーを使いたいですxmllint
。
a
次のXPath式を使用して要素間のテキストをフィルタリングします。
xmllint --html --xpath '//a/text()' <file>
答え2
PZ
aから最も近いものまですべての部分を選択するには、s16
貪欲ではない一致が必要です。これは(拡張)正規表現ではサポートされていませんが、grep
GNUにはgrep
Perlスタイルの式のerlオプションがあります。-P
grep -P -o "PZ.*?s16" ~/file
Perl 式 ".*?" は、式全体を一致させる文字のうち最も短い一致を表します。
PZ
試合の中に多くがあるので、これはまだあなたが望むものではないかもしれませんが、あなたの例を理解すると後ろにあるものだけがPZ
必要であり、s16
その間には何も必要ありません。PZ
それでは、2番目のステップで不要なアイテムを削除してみましょう。
grep -P -o "PZ.*?s16" ~/file | sed 's/.*PZ/PZ/'
答え3
これを行う方法はいくつかあります。
1PCREが有効なGNU grep。ここでは、貪欲ではない正規表現*?を負の予測と組み合わせて使用して、PZとs16の間に発生するすべてのPZを削除します。
grep -Po 'PZ(?:(?!PZ).)*?s16' file
2 そのようなgrepバージョンにアクセスできない場合は、正規表現をサポートする元のバージョンであるPerlを使用できます。
perl -lne 'print for /PZ(?:(?!PZ).)*?s16/g' file
サム これにはsedを使用できます。第1段階では、PZ及びs16をBOL及びEOLとして示す。この修正された入力は、PZで始まりs16で終わる行を選択する2番目のsedに渡され、内部的にPZを含めないでください。
< file \
sed 's/PZ/\n&/g;s/s16/&\n/g' |
sed '/^PZ.*s16$/!d;/..*PZ/d' |
cat
4 私たちを。ここでは1つのsed呼び出しのみが使用されます。 GNU sedが必要です。
sed '/\n/{
/^PZ[^\n]*s16/!D
s//&\n/;P;D;}
s/PZ/\n&/g;D
' file