web-dev-qa-db-ja.com

トークン化エラー:Java.util.regex.PatternSyntaxException、ダングリングメタキャラクター「*」

私はsplit()を使用して、この形式に従って*で区切られた文字列をトークン化します。

name*lastName*ID*school*age
%
name*lastName*ID*school*age
%
name*lastName*ID*school*age

私はこのコードを使用して「entrada.al」という名前のファイルからこれを読んでいます:

static void leer() {

    try {
        String ruta="entrada.al";
        File myFile = new File (ruta);
        FileReader fileReader = new FileReader(myFile);

        BufferedReader reader = new BufferedReader(fileReader);

        String line = null;

        while ((line=reader.readLine())!=null){
            if (!(line.equals("%"))){
                String [] separado = line.split("*"); //SPLIT CALL
                names.add(separado[0]);
                lastNames.add(separado[1]);
                ids.add(separado[2]);
                ages.add(separado[3]);
            }
        }

        reader.close();
    }

そして、私はこの例外を受け取っています:

スレッド「メイン」の例外Java.util.regex.PatternSyntaxException:インデックス0の近くでメタ文字 '*'がぶら下がる

私の推測では、元のテキストファイルに*が不足していることが原因です。どうすればそれを回避できますか?

52
andandandand

いいえ、問題は*は正規表現の予約文字であるため、エスケープする必要があります。

String [] separado = line.split("\\*");

*は「前の式が0個以上」( Pattern Javadocs を参照)を意味し、前の式を指定していないため、分割式が不正になります。これが、エラーが PatternSyntaxException であった理由です。

142
Michael Myers

regex = "?"でも同様の問題が発生しました。正規表現で何らかの意味を持つすべての特殊文字で発生します。したがって、正規表現のプレフィックスとして"\\"が必要です。

String [] separado = line.split("\\*");
6
Aniket Thakur

最初の答えはそれをカバーしています。

将来、どこか別のクラス/構造に情報を保存することになるかもしれないと推測しています。その場合、多分、結果をsplit()メソッドから配列に入れたくないでしょう。

あなたはそれを求めませんでしたが、私は退屈しているので、ここに例があります、それが役に立つことを願っています。

これは、一人の人を表すために書くクラスです。


class Person {
            public String firstName;
            public String lastName;
            public int id;
            public int age;

      public Person(String firstName, String lastName, int id, int age) {
         this.firstName = firstName;
         this.lastName = lastName;
         this.id = id;
         this.age = age;
      }  
      // Add 'get' and 'set' method if you want to make the attributes private rather than public.
} 

すると、最初に投稿した解析コードのバージョンは次のようになります(これによりLinkedListに保存され、Hashtableなどのようなものを使用できます)。


try 
{
    String ruta="entrada.al";
    BufferedReader reader = new BufferedReader(new FileReader(ruta));

    LinkedList<Person> list = new LinkedList<Person>();

    String line = null;         
    while ((line=reader.readLine())!=null)
    {
        if (!(line.equals("%")))
        {
            StringTokenizer st = new StringTokenizer(line, "*");
            if (st.countTokens() == 4)          
                list.add(new Person(st.nextToken(), st.nextToken(), Integer.parseInt(st.nextToken()), Integer.parseInt(st.nextToken)));         
            else            
                // whatever you want to do to account for an invalid entry
                  // in your file. (not 4 '*' delimiters on a line). Or you
                  // could write the 'if' clause differently to account for it          
        }
    }
    reader.close();
}
3
jdc0589

これは、*が前の文字の1つ以上の出現を示すメタ文字として使用されるためです。したがって、M *を書き込むと、MMMMMM .....というファイルが検索されます。ここでは、*を唯一の文字として使用しているため、コンパイラは複数の出現を見つけるために文字を探しているため、例外をスローします。

2
Vishal Joshi