sed - 一致しない括弧を一致させない方法

sed - 一致しない括弧を一致させない方法

括弧内の行でのみどうすればよいですか?

たとえば、「.is」行を変更し、角かっこを追加したいが閉じていない角かっこを含む行は変更しないとします。

だからこれらが変わりました。

this_thing.is 24  ->   (this_thing).is 24
that.is 50        ->   (that).is 50
a[23].is == 10    ->     a[23].is == 10
a.is true         ->   (this_thing).is 24
this_thing.is 24  ->   (this_thing).is 24

しかし、これらはそうではありません:

this_thing.is (24
((that).is 50
(a[23].is == 10
a.is ( true
(this_thing.is 24

理想的には両方ではない(いいえ)

a{.is true
this_thing{.is 24

まさか)

a[.is true
this_thing[.is 24 

/.is/のある一致がありますが、一致しない角括弧をどのように一致しますか?

答え1

個人的に、私の正規表現がこのレベルの複雑さに近づいている場合は、タスク全体をPerlに切り替えます。これは、複数の開いた中かっこ/丸括弧/中括弧を処理します。

$ perl -ne '@open=/[\[({]/g; @close=/[)\]}]/g; 
             if($#close == $#open){s/(.+?)\.is/($1).is/} print' file

またはより簡単には、次のようになります。

$ perl -pne 's/(.+?)\.is/($1).is/ if $#{/[\[({]/g} == $#{/[)\]}]/g}' file

またはより完全に、同様の状況を処理する次のようになります[}(しかし、同様の状況ではまだ失敗します)()。

  $ perl -pne '@osqb=/\[/g; @csqb=/\]/g; 
               @ocb=/\{/g; @ccb=/\}/g; 
               @op=/\(/g; @cp=/\)/g;
               if($#osqb == $#csqb && $#ocb==$#ccb && $#op == $#cp){
                    s/(.+?)\.is/($1).is/
               }' file

あなたの例を実行すると印刷されます

(this_thing).is 24
(that).is 50      
(a[23]).is == 10 
(a).is true      
(this_thing).is 24
this_thing.is (24
((that).is 50
(a[23].is == 10
a.is ( true
(this_thing.is 24
a{.is true
this_thing{.is 24
a[.is true
this_thing[.is 24 

説明する

  • perl -ne:入力ファイルを1行ずつ処理し、指定された-nスクリプトを実行します-e
  • @open=/[\[({]/g;:開いているすべての文字の外観を見つけ、結果を名前付き配列に保存します@open
  • @close=/[)\]}]/g;:上記と同じですが、グリフをオフにするために使用されます。
  • if($#close == $#open):左グリフ数が右グリフ数と同じ場合(つまり、括弧などがある場合)...
  • s/(.+?)\.is/($1).is/.is:...thenは、括弧内の自分で終わる最も短い文字列を置き換えます。
  • 最後はprint角かっこの外にあり、置き換えるかどうかにかかわらず実行されます。

答え2

terdonの答えを拡張すると、Perlを使用して実際に入れ子になった角かっこ構造を解析できます。以下は、これを行う正規表現です。

$balanced_parens_grammar = qr/
  (?(DEFINE)                         # Define a grammar
    (?<BALANCED_PARENS> 
       \(                            # Opening paren
          (?:                        # Group without capturing
              (?&BALANCED_PARENS)    # Nested balanced parens
             |(?&BALANCED_BRACKETS)  # Nested balanced brackets
             |(?&BALANCED_CURLIES)   # Nested balanced curlies
             |[^)]*                  # Any non-closing paren
           )                         # End alternation
        \)                           # Closing paren
    )
    (?<BALANCED_BRACKETS> 
       \[                            # Opening bracket
          (?:                        # Group without capturing
              (?&BALANCED_PARENS)    # Nested balanced parens
             |(?&BALANCED_BRACKETS)  # Nested balanced brackets
             |(?&BALANCED_CURLIES)   # Nested balanced curlies
             |[^\]]*                 # Any non-closing bracket
           )                         # End alternation
        \]                           # Closing bracket
    )
    (?<BALANCED_CURLIES> 
       {                             # Opening curly
          (?:                        # Group without capturing
              (?&BALANCED_PARENS)    # Nested balanced parens
             |(?&BALANCED_BRACKETS)  # Nested balanced brackets
             |(?&BALANCED_CURLIES)   # Nested balanced curlies
             |[^}]*                  # Any non-closing curly
           )                         # End alternation
        }                            # Closing curly
    )
  )
  (?<BALANCED_ANY>
     (?:
         (?&BALANCED_PARENS)    
        |(?&BALANCED_BRACKETS)  
        |(?&BALANCED_CURLIES)   
     )
  )
/x;

次のように使用してください。

if( $line =~ m/
        ^
          [^()\[\]{}]*       # Any non-parenthetical punctuation
          (?&BALANCED_ANY)?  # Any balanced paren-types
          [^()\[\]{}]*
        $
        $balanced_parens_grammar/x){
    # Do your magic here
}

婦人声明

コードは完全にテストされていません。エラーがある可能性があります。

答え3

Sedは正規表現を使用しますが、これには十分に強力ではありません。これを行うには、gawkまたは他のツールを使用してください。

これを表す文法分類には、一般文法、文脈自由文法などがある。一般言語では角かっこ一致を実行できません。したがって、この操作を確実に実行することはできません。

関連情報