web-dev-qa-db-ja.com

sed、awk、grepを使用した複数行パターンマッチ

sedawkまたはgrepを使用して複数行のパターンマッチングを実行することは可能ですか?たとえば、{}の間のすべての行を取得したいとします。

だからそれは一致することができるはずです

 1. {}
 2. {.....}
 3. {.....
.....}

最初の質問では、例として<p>を使用しました。 {および}を使用するように質問を編集しました。

26
user6106

上記のアドバイスに同意しますが、小さいか完全にアドホックではないパーサーを取得する必要があるということですが、中括弧とsedの間の複数行ブロックを一致させることは(かろうじて;-)可能です。

これは、sedコードのデバッグバージョンです。

sed -n '/[{]/,/[}]/{
    p
    /[}]/a\
     end of block matching brace

    }' *.txt

いくつかのメモ、

  • -nは、「処理されたデフォルトの印刷行がない」ことを意味します。
  • 'p'はnowを意味し、行を出力します。
  • コンストラクト/[{]/,/[}]/は範囲式です。最初のパターンに一致するものが見つかるまでスキャンすることを意味します(/[{]/)そして、2番目のパターンが見つかるまでスキャンします(/[}]/)次に、sedコードの{}の間にあるアクションを実行します。この場合、 'p'とデバッグコード。 (ここでは説明しません。使用、変更、または削除してください)。

コードが実際に{、}で区切られたブロックと一致していることを確認したら、/ [}]/a \ブロック終了デバッグを削除できます。

このコードサンプルは、中括弧のペア内にないものはすべてスキップします。上記の他の人が指摘したように、文字列や正規表現などに余分な{、}が埋め込まれていると、混乱しやすくなりますOR右中括弧が同じ行の場合、( fred.bearに感謝)

これがお役に立てば幸いです。

19
shellter

Pcregrepには-M(複数行)オプションを使用できます。

pcregrep -M '\{(\s*.*\s*)*\}' test.txt

\ sは空白(改行を含む)であるため、これは0個以上の(空白に続いて。*に続いて空白)と一致し、すべて中かっこで囲まれます。

更新:

これは貪欲でないマッチングを行うはずです:

pcregrep -n -M '\{(\n*.*?\n*)*?\}' test.txt
13
Cooper

parser.awk:

#!/usr/bin/awk -f    
function die(msg) { print msg > "/dev/stderr"; exit 1 }
BEGIN {
  FS=opener
  if (mode=="l") linewise=1
  else if (mode=="i") trim_closer=length(closer)
  else if (mode!="a") die("mode must be one of: l,i,a")
}
{
  live=level
  for (f=1; f<=NF; f++) {
    if (f>1) {
      live=++level
      if (mode=="i" && level>1 || mode=="a") printf "%s", opener
    }
    cur=$f
    level-=gsub(closer, "", cur)
    if (level<0) die("Unbalanced")
    if (!linewise) {
      cur=$f
      if (sub(".*" closer, "", cur)) printf "%s", 
        substr($f, 1, length($f) - length(cur) - (level ? 0 : trim_closer))
      else if (live) printf "%s", $f
    }
  }
  if (live) {
    if (linewise) print
    else print ""
  }
}
END { if (level>0) die("Unbalanced") }

awk -v'opener={' -v'closer=}' -v'mode=a' -f parser.awkとして呼び出します。 modeがaの場合、すべての最も外側のバランスのとれた{...}の括弧と内容を出力します。モードがiの場合、その内容のみを出力します。モードがlの場合、最も外側の{...}が始まる、開いている、または閉じるところに完全な行を出力します。

5
dubiousjim

XMLのような表現(無限に再帰的なタグ)は「通常の言語」ではないため、正規表現(regex)で解析することはできません。理由は次のとおりです。

https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/

http://www.perlmonks.org/?node_id=66835

https://stackoverflow.com/questions/1379524/textual-protocol-which-is-not-a-regular-language

5
Marcin

正規表現は、一致するネストされた括弧を見つけることができません。

検索する括弧内にネストされた括弧のペアがないことが確実な場合は、最初の閉じ括弧まで検索できます。例えば:

sed -r 's#\{([^}])\}#\1#'

これにより、「{」から「}」までのすべてのテキストがそれらの間のテキストに置き換えられます。

1
mtk358