2012-03-16 11 views
4

私が使用して(10)%(5)ABC(10,5)を置き換えることができます。再帰的なJavaの正規表現に置き換えますか?

replaceAll("ABC\\(([^,]*)\\,([^,]*)\\)", "($1)%($2)") 

が、私はABC(ABC(20,2),5)またはABC(ABC(30,2),3+2)のためにそれを行う方法を見つけ出すことができないんです。

((20)%(2))%5に変換できる場合はどうすればABC(ABC(20,2),5)に変換できますか?

おかげで、 J

答えて

1

最初の質問についてはお答えします。私は単一のreplaceAllの仕事をすることができませんでした。私はそれが達成可能であるとは思わない。しかし、私はループを使用している場合、これはあなたのための作業を行う必要があります。

String termString = "([0-9+\\-*/()%]*)"; 
    String pattern = "ABC\\(" + termString + "\\," + termString + "\\)"; 
    String [] strings = {"ABC(10,5)", "ABC(ABC(20,2),5)", "ABC(ABC(30,2),3+2)"}; 
    for (String str : strings) { 
     while (true) { 
      String replaced = str.replaceAll(pattern, "($1)%($2)"); 
      if (replaced.equals(str)) { 
       break; 
      } 
      str = replaced; 
     } 
     System.out.println(str); 
    } 

私は用語termString = "([0-9+\\-*/()%]*)"のように定義、あなたが数値式のためのパーサを書いていると仮定しています。私は、文字列を復号するためのコードを追加OPの要求を1として

(10)%(5) 
((20)%(2))%(5) 
((30)%(2))%(3+2) 

EDIT:それはこれを出力します。これは、もう少しハック前方シナリオより:

String [] encoded = {"(10)%(5)", "((20)%(2))%(5)", "((30)%(2))%(3+2)"}; 
    String decodeTerm = "([0-9+\\-*ABC\\[\\],]*)"; 
    String decodePattern = "\\(" + decodeTerm + "\\)%\\(" + decodeTerm + "\\)"; 
    for (String str : encoded) { 
     while (true) { 
      String replaced = str.replaceAll(decodePattern, "ABC[$1,$2]"); 
      if (replaced.equals(str)) { 
       break; 
      } 
      str = replaced; 
     } 
     str = str.replaceAll("\\[", "("); 
     str = str.replaceAll("\\]", ")"); 
     System.out.println(str); 
    } 

、出力は次のとおりです。

ABC(10,5) 
ABC(ABC(20,2),5) 
ABC(ABC(30,2),3+2) 
+0

Borisありがとうございます。再帰的にABC(10,5)に変換するのは難しいです。親切なアドバイス。 –

+0

私の解決策もこの質問に追加しました。 –

+0

ボリスに感謝します。デコーダは素晴らしいです。 ABC((60 + 3)、(5-3))にこのような((60 + 3))%((5-3))をデコードできるように少し変更するだけです。 –

0

あなたはポーランド記法を使用して文字列を書き換えしようとすると、その後ABC(X、Y)で任意の%X Yを置き換えることができます。

Hereのポーランド語表記のwikiリンクです。

問題

はあなたが再帰的に自分の文字列でそれらを交換したときにが最初に発生した ABC(X、Y)の書き換えを見つける必要があるということです。ポーランド表記法は、これらの書き換えが発生する順序を「解読」するのに役立ち、式の評価に広く使用されます。

これは、最初に置き換えられたスタックと記録を使用して行うことができます。一番内側の括弧を見つけ、その式だけをスタックにプッシュしてから、文字列から削除します。式の元の式を再構成する場合は、スタックの先頭から始め、逆変換を適用してください。(X)%(Y) - >ABC(X、Y)

これはポーランド表記の形式ですが、唯一の違いは、式全体を文字列として格納せずに、簡単な処理のためにスタックに格納することだけです。

要するに、交換するときは、最も内側の用語(括弧がないもの)から始め、逆置きを適用します。 >ABC {X、Y}が仲介書き換え規則として、その後、丸括弧のように中括弧を書き換える -

(X)%(Y)を使用することが有用であり得ます。このようにして、新しい用語が丸括弧を使用しないので、最も内側の用語を判別することが容易になります。また、実装が簡単ですが、エレガントではありません。

1

あなたはこれ以上の再来が存在しなくなるまで、最初の最も内側のreducable式を評価開始することができます。しかし、あなたは他の世話をする必要があります,()。 @BorisStrandjevのソリューションはより優れており、より弾力的です。

String infix(String expr) { 
    // Use place holders for '(' and ')' to use regex [^,()]. 
    expr = expr.replaceAll("(?!ABC)\\(", "<<"); 
    expr = expr.replaceAll("(?!ABC)\\)", ">>"); 
    for (;;) { 
     String expr2 = expr.replaceAll("ABC\\(([^,()]*)\\,([^,()]*)\\)", 
       "<<$1>>%<<$2>>"); 
     if (expr2 == expr) 
      break; 
     expr = expr2; 
    } 
    expr = expr.replaceAll("<<", ")"); 
    expr = expr.replaceAll(">>", ")"); 
    return expr; 
} 
0

また、再帰的な正規表現をサポートしています。この正規表現ライブラリhttps://github.com/florianingerl/com.florianingerl.util.regexを、使用することができます。

すなわち20((から、再度変換
Pattern pattern = Pattern.compile("(?<abc>ABC\\((?<arg1>(?:(?'abc')|[^,])+)\\,(?<arg2>(?:(?'abc')|[^)])+)\\))"); 
    Matcher matcher = pattern.matcher("ABC(ABC(20,2),5)"); 
    String replacement = matcher.replaceAll(new DefaultCaptureReplacer() { 
     @Override 
     public String replace(CaptureTreeNode node) { 
      if ("abc".equals(node.getGroupName())) { 
       return "(" + replace(node.getChildren().get(0)) + ")%(" + replace(node.getChildren().get(1)) + ")"; 
      } else 
       return super.replace(node); 
     } 

    }); 
    System.out.println(replacement); 
    assertEquals("((20)%(2))%(5)", replacement); 

:ABC(ABC(20,2)、5)((20)%(2))%〜(5)のようになります変換

)ABC(ABC(20,2)、5)への%(2))%(5)の割合は次のようになります:

関連する問題