例えば、ウィクショナリー辞書によると「いつ」の発音だ。 enPR、IPA、X-SAMPAは、発音を表示するさまざまな方法です。
when:* {{a|US}} {{enPR|wĕn|hwĕn}}, {{IPA|/wɛn/|/ʍɛn/}}, {{X-SAMPA|/wEn/|/WEn/}}
when
キーワードと2つのIPAの発音を抽出して別の行に配置したいと思います。
when wɛn
when ʍɛn
単語には1つ、2つ、またはそれ以上のIPAの発音があり、enPRまたはX-SAMPAの発音がある場合とない場合があります。
私はリストの中のリストであるPHPを検討していましたが、それは少し過剰であるように見えました。 awk、sed、cut、または他の標準のUnixコマンドラインユーティリティでこれを行う方法はありますか?
答え1
を使用すると、sed
次のように書くことができます。
sed '/\([^:]*\):.*{IPA|\([^}]*\).*/!d;s//\1 \2/;s,/,,g;:1
s/\(\([^ ]*\).*\)|/\1\n\2 /;t1'
分解(@slm、ありがとう)
上記のコマンドは次のように分割できます。
入力を解析し、
when: ... {IPA|...}
一致しない行を削除します。存在する
/pattern/!d; s//repl/
[!]パターンと一致しない行を削除し、次の[s]代替コマンドで同じパターンを再利用します(空のパターンは最後のパターンを再利用することを意味します)。 [d]を使用して、
b
一致しない行を変更せずに削除できますd
。あるいは、すべての行がパターンと一致することがわかっている場合は、s/pattern/repl/
直接使用できます。/\([^:]*\):.*{IPA|\([^}]*\).*/
このモードはデータを2つのブロックに分割します。最初のブロックはです
when:
。このコードは、\([^:]*\):
aが表示されるまですべての文字を取得し、:
一時的に保存するように指示します。変える(\1
)。その間
:
(含む)のすべての文字を{IPA|
スキップします。保存された次のビットはですIPA|
。これはコードブロックを使用して行われます。\([^}]*\)
つまり、}
aが表示されるまですべてのコードを保存します。これは変数(\2
)に格納されます。メモ:
sed
文字列を保存したいときはいつでもかっこで囲むことができます。文字通りの角かっこを意味しないことがわかるように、\
aでエスケープする必要があります。sed
このように:\( savethis \)
。はい
$ sed 's/\([^:]*\):.*{IPA|\([^}]*\).*/\1 \2/;' sample.txt when /wɛn/|/ʍɛn/
すべてのスラッシュを削除(
/
)これは代替区切り文字を使用するため、より複雑に見えます。通常は型を使用します
s///g
が、sed
区切り文字を動的に構成するので、代わりにコンマ(s,,,g
)を使用します。ブロックはそれを検索し、/
何もないものに置き換えます。はい
$ sed '/\([^:]*\):.*{IPA|\([^}]*\).*/!d;s//\1 \2/;s,/,,g;' sample.txt when wɛn|ʍɛn
各IPAを繰り返します。
:1 s/\(\([^ ]*\).*\)|/\1\n\2 /;t1
これはソリューションで最も複雑なコンポーネントです。何が起こっているのかわかりませんが、このブロックは条件付き分岐です。
:label command(s) t label
ラベルは、前のコマンドがパターンスペースを変更したことを確認する「テスト」であるコマンド
:1
です。その場合は、ラベルに移動して 。s/\(\([^ ]*\).*\)|/\1\n\2 /;
t label
1
t1
ループ内のコマンド
しばらくそれを取り出し、
label ... loop
IPAの例を増やして3まで上げると、何が起こっているのかをよりよく見ることができます。{{IPA|/wɛn/|/ʍɛn/|/blah/}}
これを行うには、前のコマンドを使用します。
when wɛn|ʍɛn|blah
今これを実行すると:
$ echo "when wɛn|ʍɛn|blah" | sed 's/\(\([^ ]*\).*\)|/\1 \2 /;'
私達はこれを得ます:
when wɛn|ʍɛn when blah
今何をしているのか見られますか?はい、私も同じです。もっと単純化して改行文字()を削除し、
\n
より短い文字列に置き換えます。より簡単な例
$ echo "X C1|C2|C3" | sed 's/\(\([^ ]*\).*\)|/\1 \2 /;' X C1|C2 X C3
ここで何が起こるのかは、コードが
\(\([^ ]*\).*\)|
括弧を入れ子にして次のように見えるようにするので、スマートであるということです( ( ) )
。内部括弧内の一致は空白ではありません。これはwhen
文字列です。外側ブラケットは、最後のパイプ()|
の前のすべてのものと一致します。このコードスニペットのもう一つの興味深い点は、角かっこが外部角かっこが格納され、
\1
内部角かっこが保存されるように順序付けられていることです\2
。sed
会う順番に番号が付いているからです。\1
追加の合計でスニペットを拡張すると、それを確認できます\2
。$ echo "X C1|C2|C3" | sed 's/\(\([^ ]*\).*\)|/\1 \1 \1 /;' X C1|C2 X C1|C2 X C1|C2 C3 $ echo "X C1|C2|C3" | sed 's/\(\([^ ]*\).*\)|/\1 \2 \2 /;' X C1|C2 X X C
したがって、ループ内のコマンドはデフォルトで
X
2回実行されます。一度は全体の一部X C1|C2
(括弧の外側)、2番目はスペースの一部(括弧の内側)として使用されます。条件付き分岐を返す
さて、ブランチはデフォルトで#5のコマンドを呼び出し、IPAの場合は2つ以上あります。
sed
分岐構成は、コマンドが代替エントリを変更しなくなるまでコマンドを再実行し、その時点で停止します。はい
$ echo "X C1|C2|C3" | sed ':1 s/\(\([^ ]*\).*\)|/\1\n\2 /; t1' X C1 X C2 X C3
上記の内容が今後他の行人がこの回答を見つけるのに役立つことを願っています。
答え2
PerlスクリプトでPerlを使用する(処理STDIN
)
while(<>) {
if(/^([^:]+):.*{{IPA\|([^}]+)}}/) {
print "$1 $_\n" foreach(split /\|/, $2);
}
}
またはコマンドライン(パイプライン)から
perl -ne ' if(/^([^:]+):.*{{IPA\|([^}]+)}}/) { print "$1 $_\n" foreach(split /\|/, $2); }'
答え3
bashとgrepを使う
line='when:* {{a|US}} {{enPR|wĕn|hwĕn}}, {{IPA|/wɛn/|/ʍɛn/}}, {{X-SAMPA|/wEn/|/WEn/}}'
IFS=$': \t' read -ra words <<< "$line"
for item in "${words[@]}"; do
if [[ $item == "{{IPA|"* ]]; then
grep -o '/[^/]\+/' <<< "$item" | while read -r pronunc; do
echo "${words[0]} ${pronunc//\//}"
done
fi
done