これはsed
具体的な質問です。他のツールを使用してこれを行うことができることはよく知っていますが、知識を拡張したいと思いますsed
。
sed
スクリプトで指定されていない単語にグローバル引用符(実際には逆引用符)をどのように使用できますか?単語は予約済みスペースに保存されます。
私が望むのはこれです:
s/word/`&`/g
しかし、秘密は、word
sedスクリプトではなく予約されたスペースに含めることです。したがって、次のように見えます。
H
g
s/^\(.*\)\n\(.*\)\1\(.*\)$/\2`\1`\3/
これは参考になります。一つ予約済みスペースで予約語が発生します。引用したいみんなg
ただし、静的正規表現の代わりに逆参照を使用するため、フラグを追加することはできません。
H
g
s/^\(.*\)\n\(.*\)\1\(.*\)\1\(.*\)$/\2`\1`\3`\1`\4/
これは単語の2つの発生を処理しますが、一度失敗し、複数の発生は無視されます。
私は次のようにきれいでシンプルなものを使用できると思いました。
s//`&`/g
しかし、これは最後に使用したものを再利用します正規表現、一致するものではありません。 (これは言葉になる。)
sed
私が望むことをする方法はありますか? (事実は私です会議でこれがどれほど簡単かを知りたいのですが、perl
まだでこれを行う方法を知りたいですsed
。 )
修正する
そうではありません必要しかし、私はこの質問をするとき、私が正確に何をしていたのかについての背景知識をもう少し提供しなければならないと思いました。
大容量の文書テキストファイルがあり、その一部を圧縮してテーブルにまとめる必要がありますasciidoc
。これはDescription:
行などによって非常に簡単なので、実際にすべての解析を実行するクイックPrototype:
スクリプトを作成しました。うまくいきますが、欠けているのは、その行にリストされているパラメータと一致する行の単語を逆引用符で表示したいことsed
です。プロトタイプラインは次のとおりです。Description
Prototype
Prototype: some_words_here(and, arg, list,here)
私が出力するテーブルには200を超える項目があります(ソース文書にはこれよりはるかに多くのテキストが含まれています)、各引数リストには一致する単語を引用するためにバックティックのみが必要です。一つワイヤー。もっと難しいのは、いくつかのパラメータが説明行になく、いくつかのパラメータが複数回表示され、いくつかのパラメータリストが空であることです()。
しかし、時にはargが一致する可能性があることを考慮してください。部分単語名とバックティックが欲しくない場合によっては、arg名が一般的な単語(例from
:)であり、関数の使用を説明する文脈で使用するときにバックティック(自動)が必要です。解決策は実際にはまったく合っておらず、代わりにvim
いくつかのトリッキーなマクロの助けを借りて半分の手作業を行いました。 :)
答え1
それは難しいことです。あなたがこれを持っているとしましょうfile
:
$ cat file
word
line with a word and words and wording wordy words.
どこ:
- 行1:予約済みスペースに保存して参照する必要がある検索パターン
`word`
。 - 2行目:グローバル検索と置換のための行。
注文するsed
:
sed -n '1h; 2{x;G;:l;s/^\([^\n]\+\)\n\(.*[^`]\)\1\([^`]\)/\1\n\2`\1`\3/;tl;p}' file
説明する:
1h;
最初の行を予約済みスペースに保存します(これは私たちが検索したい待機です)。- 宿泊スペースには以下が含まれます:
word
- 宿泊スペースには以下が含まれます:
2{...}
2行目に適用されます。x;
パターンスペースを変更してスペースを維持します。G;
予約済みスペースをパターンスペースに追加します。パターン空間には以下があります。
word # I will call this line the "pattern line" from now on
line with a word and words and wording wordy words.
:l;
l
後で使用できるように、ポイントという名前のラベルを設定してください。s///
上記のパターン空間で実際の検索/置換を実行します。^\([^\n]\+\)\n
^
行の先頭から[^\n]
(1回以上\+
)改行文字まで始めて、改行文字以外のすべての文字の「パターン行」を検索します\n
。これで逆参照に保存されました\1
。これには「パターンライン」が含まれています。(.*[^`])
.*
後ろに文字(バックティックではない)が続くすべての文字を検索します[^`]
。これはに保存されます\2
。これで、\2
次のものが含まれます。line with a word and words and wording wordy
word
\1
は次の検索語(逆参照\1
、word
)なので、「パターンライン」に含まれる内容です。([^`])
参照に保存されている逆引用符以外の文字が続きます\3
。この操作(および上記の部分)を実行しないと、同じ->を参照し続ける\2
無限ループに陥ります。なぜなら、常に成功して再びジャンプするからです(下記参照)。word
````word````
s///
tl;
:l
tl;
\1\n\2
上記の内容はすべて逆参照に置き換えられます。 2番目は\1
\3\1
私たちが引用すべき内容です(最初の引用は「パターンライン」です)。
tl;
成功したらs///
(何かを置き換える)名前付きタグにジャンプしてl
検索し、置き換えるコンテンツがなくなるまで再起動します。これは、その単語がすべて置換/引用される場合です。p;
すべてのジョブが完了したら、変更された行(パターンスペース)を印刷します。
出力:
$ sed -n '1h; 2{x;G;:l;s/^\([^\n]\+\)\n\(.*[^`]\)\1\([^`]\)/\1\n\2`\1`\3/;tl;p}' file
word
line with a `word` and `word`s and `word`ing `word`y `word`s.
答え2
ルックアップテーブルは難しい場合があります。そして非常に高価です- パターン空間の両端を同時に検索しなければならないからです。しかし、実装するのは少なくともやや簡単です。何をしても、一度に1つのゲームしか安定して処理できないことを考慮する必要があります。したがって、g
世界的な結果を得るための希望を放棄することをお勧めします。とにかく、それは状況を混乱させるだけです。コンパイルされた式を使用せずに実際に副作用を扱っています。両方両側から始めてください。
printf %s\\n some words to match \
'and some words and some more words to match them against' |
sed -ne'$!{H;d;}' -e'G;s/\(\n\).*/\1&\1/;tm' -e:m \
-e 's/\(.\)\(.*\)\(.*\n\n.*\n\1\2\(\n\)\)/`\1\4\2`\3/;tm'
これがメインループです。まだ掃除をしていないので、実際には動作しませんが、基本的な問題を解決します。同じパターン空間を繰り返し繰り返す必要がありますが、一致が2回一致しないことをどのように確認できますか?区切り記号で終わると、再び一致が発生し、ブックエンドが無限に積み重ねられます。
ここで使用する解決策は、ゲームを破ることです。もちろん、最初の文字が一致した後に改行を挿入します。もちろん、まだクリーンアップが必要です。そのことは私が処理します。ただし、ルックアップテーブルに他のメンバーのサブセットが含まれている場合、または単一の文字セットを使用している場合は、まだ機能しません。これを行う方法はさまざまで、より良い方法もあります。必要に応じていくつかの選択肢をお知らせします。
詳細は次のとおりです。
printf %s\\n some words to match \
'and some words and some more words to match them against' |
sed -ne'$!{H;d;}' -e'G;s/\(\n\).*/\1&\1/;tm' -e:m \
-e 's/\(.\)\(.*\)\(.*\n\n.*\n\1\2\(\n\)\)/`\1\4\2`\3/;tm' \
-e l
and `s\nome` `w\nords` and `s\nome` more `w\nords` `t\no` `m\natch` \
them against\n\n\nsome\nwords\nto\nmatch\n$
もちろん整理も簡単です。
printf %s\\n some words to match \
'and some words and some more words to match them against' |
sed -ne'$!{H;d;}' -e'G;s/\(\n\).*/\1&\1/;tm' -e:m \
-e 's/\(.\)\(.*\)\(.*\n\n.*\n\1\2\(\n\)\)/`\1\4\2`\3/;tm' \
-e 's/\(`.\)\n/\1/g;P'
and `some` `words` and `some` more `words` `to` `match` them against
少なくともg
世界中でこれを行うことができます。
この種のタスクを実行するために私が好む方法は、実際にスクリプトを書くことです。
printf %s\\n some words to match \
'and some words and some more words to match them against' |
{ sed -e"$(
sed -ne'$w /dev/fd/3' -e$\q \
-e 's/[]\^$/.*[]/\\&/g' \
-e 's|..*|s/&/`\&`/g|p'
)" <&3
} 3<<"" 3<>/dev/fd/3
and `some` `words` and `some` more `words` `to` `match` them against
sed
コマンド内置換は、すべての入力行でメタ文字をエスケープするように注意してから、置換ステートメントを作成します(ただし、最後の文字には含めることができます)sed
s///
。最後の行はw
文字通り共有されたhere-docファイル記述子に書き込まれるため、sed
外部から入力として読み取ることができます。内部的には、sed
次のように動作するスクリプトを印刷します。
sed -e's/some/`&`/g' \
-e's/words/`&`/g' \
-e's/to/`&`/g' \
-e's/match/`&`/g'
...そして最後の行を他の人に渡してsed
作業させます。