2

[some name] を [some_name] に変換するには、次の式を使用する必要があることがわかりました。

s/\(\[[^ ]*\) /\1_/

i.e. create a backreference capture for anything that starts with a literal '[' that contains any number of non space characters, followed by a space, to be replaced with the non space characters followed by an underscore. What I don't know yet though is how to alter this expression so it works for ALL underscores within the braces e.g. [a few words] into [a_few_words].

I sense that I'm close, but am just missing a chunk of knowledge that will unlock the key to making this thing work an infinite number of times within the constraints of the first set of []s contained in a line (of SQL Server DDL in this case).

Any suggestions gratefully received....

4

2 に答える 2

3

必要な策略には 2 つの部分があります。

  1. 閉じた角括弧に到達したら置換を停止します (ただし、行で繰り返し実行します)。

    s/\(\[[^] ]*\) /\1_/g
    

    これは、開き角括弧の後に、空白でも閉じ角括弧でもない 0 個以上の文字が続くものと一致します。グローバル接尾辞は、行の左角括弧で始まり、最終的に空白または右角括弧が続くすべてのシーケンスにパターンが適用されることを意味します。また、この正規表現は ' ' を変更しないことに注意してください。[single-word] and context元の正規表現はそれを ' ' に変換し[single-word]_and contextますが、これは演習の目的ではありません。

  2. sed を取得して、この検索が開始された場所から検索を繰り返します。残念ながら、それを行う本当に良い方法はありません。Sed は常に、置換されたテキストの後で検索を再開します。これは、それを望まない場合の 1 つです。代用操作を繰り返すだけで済む場合もあります。この場合、置換が成功するたびにそれを繰り返す必要があり、置換がなくなると停止します。

あまり知られていない 2 つの操作sedは、 ' ' コマンド:labelと ' t' コマンドです。ただし、それらは Unix の第 7 版 (1978 年頃) に存在していたため、新しい機能ではありません。b1 つ目は、' ' (ここでは不要) または ' t'でジャンプできるスクリプト内の位置を単純に識別します。

[2addr]t [label]

:入力行の最新の読み取りまたは ' ' 関数の実行以降に置換が行われた場合、ラベルを持つ' ' 関数に分岐しtます。ラベルが指定されていない場合は、スクリプトの最後に分岐します。

すばらしい: 必要なもの:

 sed -e ':redo; s/\(\[[^] ]*\) /\1_/g; t redo' data.file

ただし、そのような 1 行ですべてが機能するわけではありません (少なくとも、MacOS X ではそうではありません)。ただし、これは見事に機能しました。

sed -e ':redo
        s/\(\[[^] ]*\) /\1_/g
        t redo' data.file

または、コメントに記載されているように、3 つの個別の「-e」オプションを記述できます (これは MacOS X で動作します)。

 sed -e ':redo' -e 's/\(\[[^] ]*\) /\1_/g' -e 't redo' data.file

次のデータ ファイルを指定します。

a line with [one blank] word inside square brackets.
a line with [two blank] or [three blank] words inside square brackets.
a line with [no-blank] word inside square brackets.
a line with [multiple words in a single bracket] inside square brackets.
a line with [multiple words in a single bracket] [several times on one line]

表示されている sed スクリプトからの出力は次のとおりです。

a line with [one_blank] word inside square brackets.
a line with [two_blank] or [three_blank] words inside square brackets.
a line with [no-blank] word inside square brackets.
a line with [multiple_words_in_a_single_bracket] inside square brackets.
a line with [multiple_words_in_a_single_bracket] [several_times_on_one_line]

そして最後に、質問の細字を読んで、各行の最初の角括弧で囲まれたフィールドでのみこれを行う必要がある場合は、一致を開始する角括弧の前に開いた角括弧がないことを確認する必要があります. このバリアントは動作します:

sed -e ':redo' -e 's/^\([^]]*\[[^] ]*\) /\1_/' -e 't redo' data.file

(「g」修飾子はなくなりました - ループを考えると、おそらく他のバリアントでは必要ありません。その存在により、プロセスがわずかに効率的になる可能性がありますが、それを検出することは本質的に不可能である可能性が最も高いでしょう。パターンは現在行頭 (キャレット) に固定され、最初の左角括弧の前に左角括弧以外の文字が 0 個以上含まれています。)

出力例:

a line with [two_blank] or [three blank] words inside square brackets.
a line with [no-blank] word inside square brackets.
a line with [multiple_words_in_a_single_bracket] inside square brackets.
a line with [multiple_words_in_a_single_bracket] [several times on one line]
于 2010-12-21T21:35:28.137 に答える
1

これは、「実行可能な」置換を持つ perl のような言語では簡単です。

perl -wne 's/(\[.*?])/ do { my $x = $1; $x =~ y, ,_,; $x } /ge; print'

または、より明確に分割するには:

sub replace_with_underscores {
    my $s = shift;
    $s =~ y/ /_/;
    $s
}
s/(\[.*?])/ replace_with_underscores($1) /ge;

これ.*?は貪欲ではない一致 (2 つの隣接する角かっこで囲まれたフレーズを一緒に中傷することを避けるため) でありe、置換へのフラグによってそれが評価されるため、関数を呼び出して内部作業を行うことができます。

于 2010-12-21T21:48:55.363 に答える