464

sed を使用して URL の行をクリーンアップし、ドメインだけを抽出しようとしています。

だからから:

http://www.suepearson.co.uk/product/174/71/3816/

私が欲しい:

http://www.suepearson.co.uk/

(末尾のスラッシュの有無に関係なく)

私が試してみました:

 sed 's|\(http:\/\/.*?\/\).*|\1|'

そして(貪欲でない量指定子をエスケープする)

sed 's|\(http:\/\/.*\?\/\).*|\1|'

しかし、貪欲でない量指定子 ( ) を機能させることができないように見える?ため、常に文字列全体に一致することになります。

4

27 に答える 27

465

基本的な Posix/GNU 正規表現も拡張された Posix/GNU 正規表現も、貪欲でない量指定子を認識しません。後で正規表現が必要です。幸いなことに、このコンテキストの Perl 正規表現は非常に簡単に取得できます。

perl -pe 's|(http://.*?/).*|\1|'
于 2009-07-09T10:58:23.387 に答える
297

この特定のケースでは、貪欲でない正規表現を使用せずに仕事を終わらせることができます。

[^/]*代わりに、この貪欲でない正規表現を試してください.*?:

sed 's|\(http://[^/]*/\).*|\1|g'
于 2009-07-09T10:51:34.693 に答える
141

sed では、通常、セパレーターまでセパレーター以外のものを検索することで、貪欲でない検索を実装します。

echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*\)/.*;\1;p'

出力:

http://www.suon.co.uk

これは:

  • 出力しない-n
  • 検索、パターン一致、置換、印刷s/<pattern>/<replace>/p
  • 入力を容易にする;代わりに、検索コマンドセパレーターを使用してください。/s;<pattern>;<replace>;p
  • 括弧間の一致を記憶\(... \)、後で\1, \2...でアクセス可能
  • マッチhttp://
  • []かっこ内に何かが続く場合は、またはまたは[ab/]のいずれかを意味しますab/
  • 最初^[]手段notであり、その後にその中のもの以外のものが続きます[]
  • soは文字[^/]以外のすべてを意味します/
  • *は前のグループを繰り返すため、[^/]*以外の文字を意味します/
  • so farsed -n 's;\(http://[^/]*\)は、search and rememberの後に、見つかったものhttp://以外の任意の文字が続くことを意味/します。
  • ドメインの最後まで検索したいので、次で停止するので、最後/に別の行を追加します/:sed -n 's;\(http://[^/]*\)/'しかし、ドメインの後の行の残りの部分と一致させたいので、追加します.*
  • グループ 1 ( ) で記憶されている\1一致がドメインであるため、一致した行をグループに保存されているものに置き換え\1て印刷します。sed -n 's;\(http://[^/]*\)/.*;\1;p'

ドメインの後にバックスラッシュも含めたい場合は、覚えておくためにグループにバックスラッシュをもう 1 つ追加します。

echo "http://www.suon.co.uk/product/1/7/3/" | sed -n 's;\(http://[^/]*/\).*;\1;p'

出力:

http://www.suon.co.uk/
于 2012-12-20T23:36:55.853 に答える
39

での怠惰な (貪欲でない) 量指定子のシミュレートsed

そして他のすべての正規表現のフレーバー!

  1. 式の最初の出現を見つける:

    • POSIX ERE (-rオプションを使用)

      正規表現:

        (EXPRESSION).*|.
      

      セド:

        sed -r ‍'s/(EXPRESSION).*|./\1/g' # Global `g` modifier should be on
      

      例 (数字の最初のシーケンスを見つける)ライブ デモ:

        $ sed -r 's/([0-9]+).*|./\1/g' <<< 'foo 12 bar 34'
      
        12
      

      それはどのように機能しますか?

      この正規表現は、代替の恩恵を受けます|。各位置で、エンジンは最長一致を選択しようとします (これは POSIX 標準であり、他のいくつかのエンジンもこれに従います)。これは.、一致が見つかるまで続けることを意味し([0-9]+).*ます。しかし、順序も重要です。

      ここに画像の説明を入力

      グローバル フラグが設定されているため、エンジンは入力文字列またはターゲットの末尾まで、文字ごとに一致を継続しようとします。交互の左側の最初で唯一のキャプチャ グループが一致すると(EXPRESSION)すぐに、残りの行もすぐに消費されます.*。これで、最初のキャプチャ グループに値が保持されます。

    • POSIX BRE

      正規表現:

        \(\(\(EXPRESSION\).*\)*.\)*
      

      セド:

        sed 's/\(\(\(EXPRESSION\).*\)*.\)*/\3/'
      

      例 (数字の最初のシーケンスを見つける):

        $ sed 's/\(\(\([0-9]\{1,\}\).*\)*.\)*/\3/' <<< 'foo 12 bar 34'
      
        12
      

      これは ERE バージョンに似ていますが、変更は含まれていません。それで全部です。各単一位置で、エンジンは数字を一致させようとします。

      ここに画像の説明を入力

      それが見つかった場合、他の次の数字が消費されてキャプチャされ、残りの行がすぐに照合されます。それ以外の場合* 2 番目のキャプチャ グループをスキップし\(\([0-9]\{1,\}\).*\)*てドット.に到達し、このプロセスが続行されます。

  2. 区切り式の最初の出現を見つける:

    このアプローチは、区切られた文字列の最初の出現に一致します。これを文字列のブロックと呼ぶことができます。

    sed 's/\(END-DELIMITER-EXPRESSION\).*/\1/; \
         s/\(\(START-DELIMITER-EXPRESSION.*\)*.\)*/\1/g'
    

    入力文字列:

    foobar start block #1 end barfoo start block #2 end
    

    -EDE:end

    -SDE:start

    $ sed 's/\(end\).*/\1/; s/\(\(start.*\)*.\)*/\1/g'
    

    出力:

    start block #1 end
    

    最初の正規表現\(end\).*は、最初の終了区切り文字endと一致してキャプチャし、置換はすべて、終了区切り文字である最近キャプチャされた文字と一致します。この段階での出力は次のとおりfoobar start block #1 endです。

    ここに画像の説明を入力

    \(\(start.*\)*.\)*次に、結果は上記の POSIX BRE バージョンと同じ2 番目の正規表現に渡されます。開始区切り文字startが一致しない場合は 1 文字と一致し、それ以外の場合は開始区切り文字と一致してキャプチャし、残りの文字と一致します。

    ここに画像の説明を入力


あなたの質問に直接答える

アプローチ #2 (区切り式) を使用すると、2 つの適切な式を選択する必要があります。

  • EDE:[^:/]\/

  • SDE:http:

使用法:

$ sed 's/\([^:/]\/\).*/\1/g; s/\(\(http:.*\)*.\)*/\1/' <<< 'http://www.suepearson.co.uk/product/174/71/3816/'

出力:

http://www.suepearson.co.uk/

注: これは、同一の区切り文字では機能しません。

于 2016-09-28T16:26:21.600 に答える
38

sed は「貪欲でない」演算子をサポートしていません。

「/」を一致から除外するには、「[]」演算子を使用する必要があります。

sed 's,\(http://[^/]*\)/.*,\1,'

PS バックスラッシュ「/」は必要ありません。

于 2009-07-09T11:08:44.723 に答える
20

複数の文字に対する貪欲でない解決策

このスレッドは非常に古いものですが、人々はまだそれを必要としていると思います. の最初の出現まですべてを殺したいとしましょうHELLO。あなたは言うことができません[^HELLO]...

したがって、適切な解決策には 2 つのステップが含まれます。たとえば、入力で予期しない一意の単語を省略できると仮定しますtop_sekrit

この場合、次のことができます。

s/HELLO/top_sekrit/     #will only replace the very first occurrence
s/.*top_sekrit//        #kill everything till end of the first HELLO

もちろん、より単純な入力では、より短い単語や 1 文字を使用することもできます。

チッ!

于 2013-10-30T13:05:53.770 に答える
17

これは、カットを使用して実行できます。

echo "http://www.suepearson.co.uk/product/174/71/3816/" | cut -d'/' -f1-3
于 2010-12-10T01:02:01.880 に答える
9

正規表現を使用しない別の方法は、フィールド/区切り文字メソッドを使用することです。

string="http://www.suepearson.co.uk/product/174/71/3816/"
echo $string | awk -F"/" '{print $1,$2,$3}' OFS="/"
于 2009-07-09T10:59:12.713 に答える
3
sed 's|(http:\/\/[^\/]+\/).*|\1|'
于 2009-07-09T10:58:59.563 に答える
3

sed -E は、正規表現を拡張 (現代) 正規表現として解釈します

更新: MacOS X では -E、GNU sed では -r。

于 2009-07-09T11:25:07.433 に答える
1

ここでは PCRE もタグ付けされているため、正規表現でgrep非遅延一致を使用して GNU を使用できます。.*?.*

grep -oP '^http[s]?:\/\/.*?/' Input_file

説明:grepここでのoPオプションを使用-PPCRE 正規表現を有効にする責任があります。grep一致する正規表現を言及するメイン プログラムでは、://から次の出現まで/.*?ます/。一致した部分のみをインラインで印刷します。

于 2021-11-15T06:21:40.327 に答える
1

これは古いエントリだと思いますが、誰かが役に立つと思うかもしれません. 完全なドメイン名は合計で 253 文字を超えることはできないため、.* を .\{1, 255\} に置き換えます。

于 2011-06-29T15:49:11.953 に答える
0

別の sed バージョン:

sed 's|/[:alnum:].*||' file.txt

これ/は、その後に続く英数字 (別のスラッシュではない) と、行末までの残りの文字に一致します。その後、何も置き換えません (つまり、削除します)。

于 2016-02-02T00:03:00.653 に答える
0
echo "/home/one/two/three/myfile.txt" | sed 's|\(.*\)/.*|\1|'

気にしないでください、私は別のフォーラムでそれを手に入れました:)

于 2010-12-10T01:20:36.997 に答える
-1

残念ながら、前述のように、これは sed ではサポートされていません。これを克服するには、vim sed のような機能を使用するために、次善の策 (実際にはさらに良い) を使用することをお勧めします。

定義する.bash-profile

vimdo() { vim $2 --not-a-term -c "$1"  -es +"w >> /dev/stdout" -cq!  ; }

これにより、コマンドを実行するためのヘッドレス vim が作成されます。

たとえば、次のことができます。

echo $PATH | vimdo "%s_\c:[a-zA-Z0-9\\/]\{-}python[a-zA-Z0-9\\/]\{-}:__g" -

で python を除外し$PATHます。

-vimdo でパイプからの入力を取得するために使用します。

ほとんどの構文は同じですが。Vim はより高度な機能を備えており、\{-}非貪欲な一致では使用が標準です。を参照してくださいhelp regexp

于 2022-01-03T00:09:28.513 に答える