2016-09-21 11 views
2

私は特定のパターンで文字列を収集する必要がある次のパターンのための正規表現を構築するための助けが必要です。Java Regex building

サンプル入力文字列:

*! 
hostname ${hostname} ! 
! 
! 
ip name-server ${ip-name-server} 
no ipv6 cef 
! 
! 
voice class codec 1 
codec preference 1 ${codec-pref-1} codec preference 2 ${codec-pref-2}  codec preference 3 ${codec-pref-3} ! 
! 
session target dns:${session-targ-DNS} dtmf-relay rtp-nte* 

出力は ホスト名、 IP-ネームサーバ、 コーデック-県-1、 コーデック-県-2、 する必要がありますcodec- pref-3, session-targ-DNS、

つまり、$ {string}の形式の文字列を収集して取得する必要があります。

私は

public void fetchKeyword(String inputString) { 
     String inputString1 = inputString.replace("\n", " "); 
     Pattern p = Pattern.compile("\\${$1} "); 
     Matcher m = p.matcher(inputString1); 
     int i=0; 
     while(m.find()){ 
      System.out.println(m.group(i)); 
      i++; 
     } 
    } 

以下のようなコードを試してみました。また、私はパターンが.${.*}(.)${.*?}などが好き試みたが、予想通り何の結果は来ませんでした。私は以下のような例外を持っています

Exception in thread "main" java.util.regex.PatternSyntaxException: Illegal repetition near index 1 
\${$1} 
^ 
    at java.util.regex.Pattern.error(Unknown Source) 
    at java.util.regex.Pattern.closure(Unknown Source) 
    at java.util.regex.Pattern.sequence(Unknown Source) 
    at java.util.regex.Pattern.expr(Unknown Source) 
    at java.util.regex.Pattern.compile(Unknown Source) 
    at java.util.regex.Pattern.<init>(Unknown Source) 
    at java.util.regex.Pattern.compile(Unknown Source) 
    at myUtil.ReplaceString.fetchKeyword(ReplaceString.java:70) 
    at myUtil.ReplaceString.main(ReplaceString.java:20) 

誰でも同じようにお手伝いできますか?

+0

'{'と '}'は正規表現では特別です( 'x {3,5}'(xは3〜5回繰り返されます)のような限定的な繰り返しを指定できます)。だから、 '$'だけでなく、それらもエスケープする必要があります。 – RealSkeptic

答えて

2

あなたは、プレースホルダのテキスト取得するために、このソリューションを使用することができます。

// test string 
String input = "! hostname ${hostname} ! ! ! ip name-server " 
      + "${ip-name-server} no ipv6 cef ! ! " 
      + "voice class codec 1 codec preference 1 ${codec-pref-1} " 
      + "codec preference 2 ${codec-pref-2} codec preference 3 " 
      + "${codec-pref-3} ! ! session target " 
      + "dns:${session-targ-DNS} dtmf-relay rtp-nte"; 

// compiling pattern with one group representing the text inside ${} 
Pattern p = Pattern.compile("\\$\\{(.+?)\\}"); 
// initializing matcher 
Matcher m = p.matcher(input); 
// iterating find 
while (m.find()) { 
    // back-referencing group 1 each find 
    System.out.println(m.group(1)); 
} 

出力を

hostname 
ip-name-server 
codec-pref-1 
codec-pref-2 
codec-pref-3 
session-targ-DNS 

注意あなたが使用$1イディオムを再で採用されて

  • プレースメント(すなわちString#replaceAll)を使用して、索引付けされたグループを逆参照します。グループの名前として
  • インデックスグループは、()として、またはJava 7以降、あなたのパターンの中で宣言されています(?<name>X)
  • グループのインデックスがパターン内ではなく、試合の繰り返しによってグループ化イディオムの発生によって定義されますあなたは
  • 参照ドキュメントhere
  • を想定しているように見えるように私は、一例として示していたパターンが注目に値する。また${}文字
  • をエスケープダブルで、それは消極的資格を使用していますまで、次の既知の文字できるだけ一致させるためにntifier(+?):最後に、上述したグループ#1は括弧内に定義され、(閉鎖}まで)任意の文字を表すよう}
  • あなたの入力テキストで
  • 改行は、このようなケースが発生した場合に限り、何の改行が${something}イディオム
  • を発生しないよう、あなたが改行のテキストをクリーンアップする必要がありますいずれかのこのパターンの結果にマイナスの影響を与えることはありません解析する前に、またはパターンをPattern.DOTALLでパラメータ化し、その後の試合での改行(後者は素晴らしい解決策のようには見えません)
  • Thomasと言えば、このパターンは{}の間の式が空でないと仮定しています。空の式がある場合は、空の式の先頭から次の空でない空の式の終わりまでのすべてを解析することで失敗します。したがって、空の式がないこと、または.+?の代わりに.*?を使用することが保証されているかどうか(Thomasの回答も参照してください)。
+0

非常に良い内訳。しかし、躊躇している量限定子についてのヒントが1つあります。データに空のタグが含まれているとします。 '$ {} ... $ {b}'の式は、次の空でないタグの最初と最後の間のすべてにマッチします。つまり、上記の例では '} ... $ {b'です。 – Thomas

+0

@トーマスは分析のおかげで - 修正されます! – Mena

3

m.group(i)が正しくありません。グループはそれぞれの一致で同じインデックスを持ち、正規表現に基づいています。キャプチャグループがないので、マッチ全体を意味するインデックス0しか使用できません。

また、バックリファレンス$1は置換文字列で使用できますが、正規表現では使用できません。数字はキャプチャグループにも基づいています。すなわち、$1はグループインデックス1(これは持っていません)を意味します。空のタグ、すなわち${}をキャッチするために、ここで私は、「任意の」-quantifier(*)を使用していることに注意してください:

このように非常に可能性があなたの式は次のようになります。\$\{([^}]*)\}

編集。それらは何らかのエラーを表している可能性が非常に高いので、おそらくそれらを捕まえて処理したいと思うでしょう。それをやりたくない場合(スキップしたい場合は、「少なくとも1つ」の-quantifier(+)を使用してください)。

私はまた、明示的な否定文字クラス([^}]からない右中括弧だすべてのもの)を使用代わりに、単純な理由.*?のような消極的数量詞のを:それは(私の意見では)より明示的にし、より読みやすいですし、エラーが起こりにくい。

例では、データに空のタグがある可能性があり、無視したいとします。\$\{.+?\}を使用しながら\$\{[^}]+\}を使用すると、にそれらを無視する(正規表現エンジンは、左から右に一致させようと)によるshortesに${}...${b}における可能な一致が}...${bあろうそれらを含むであろう。

壊滅的なバックトラック(たとえば、別の数量詞を追加する場合など)になると、安全性が向上する可能性があります。あなたが提供した単純なケースでは問題にならないかもしれませんが、(.+)*のようなものはあなたの正規表現エンジンを殺すかもしれないことに留意してください。

+0

ありがとうございます。残念ながら、私は1つの答えだけをチェックすることができます。このパターンは機能します。説明もありがとう。 –

+0

あなたはそれをupvoteすることができますし、それはまた、 "有益な"とマークされています –

+0

プラス1つから私。この中の量子は、0個以上の文字のマッチにマッチしますが、これは空の '$ {} 'を検証するかもしれません。 – Mena