質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

  • Java

    14419questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • 正規表現

    830questions

    正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

  • XML

    691questions

    XMLは仕様の1つで、マークアップ言語群を構築するために使われています。

javaの正規表現について

解決済

回答 3

投稿

  • 評価
  • クリップ 0
  • VIEW 410

travel_saki

score 4

現在、サーバとの通信の中で特定のxmlメッセージを取り出す処理を実装をしようと思っています。
色々と調べてみて、分からなかった点がありましたので質問を投稿させて頂きました。

<name>A</name><name>B</name><name>C</name>

上記のように、同一タグで複数のデータが入っているxmlデータの場合にJavaのPatternとMatcherを用いて各データを取り出そうと考えていまして、現在は次のように実装しています。

// 判定する文字列
String str = "<name>A</name><name>B</name><name>C</name>";

// 判定するパターンを生成
Pattern p = Pattern.compile("<name>.*</name>");
Matcher m = p.matcher(str);

// 出力
System.out.println(m.group());

このPatternとMatcherを用いて一致する部分を検索しようとした際に、上記のコードでは「<name>A</name><name>B</name><name>C</name>」と全部出力されます。正規表現だけを用いて「<name>A</name>」「<name>B</name>」「<name>C</name>」の3つを取り出して配列かリストに格納したいです。私の実装方法が悪いと思うのですが、、、よろしくお願いしますm(_ _)m

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 3

checkベストアンサー

+2

対策は2つあります。

  • 最短一致を使う
  • 最長一致で </name> を乗り越えない正規表現パターンを指定する

最短一致の解は既に示されているので、後者のパターンを書きます。

 最長一致

Pattern p = Pattern.compile("<name>[^<]*</name>");

この書き方はname要素の子に他のタグが存在しない場合に機能します。
他のタグが入る可能性があるなら、次のように書きます。

Pattern p = Pattern.compile("<name>[^<]*(?:<(?!/?name>)[^>]*>[^<]*)*</name>");

この書き方はname要素が入れ子にならない前提で書いてます。
入れ子になる場合は <name> と </name> を同数消費する必要がありますが、説明が複雑化する為、ここでは省略します。

 最短一致の問題点

最短一致は簡単に見えますが、バックトラックが発生するので最長一致パターンよりはどうしても遅くなります。

Pattern p = Pattern.compile("<name>.*?</name>");

上記正規表現をマッチさせる前提で、後続に </name> がN個存在したとするなら、バックトラック回数は「N * (N - 1) / 2」回です。
name要素が増える程、遅くなる計算になります。
そして、「name要素の内容となる文字列長」「</name>と<name>間の文字列長」が長ければ、それだけ文字列の消費量が多くなるので、更に遅くなります。

最短一致(*?)の後続に複数のタグが存在する場合に期待通りに動作しない点にも注意が必要になります。
例えば、正規表現パターンを次のように変更した場合、

Pattern p = Pattern.compile("<class><name>.*?</name></class>");

次の文字列の全体「"<class><name>.foo</name>bar</class>piyo</name></class>"」にマッチしてしまいます。

"<class><name>.foo</name>bar</class>piyo</name></class>"

最短一致は後続の正規表現パターン全体に依存するので、</name></class>が来るまで盲目的に消費してしまいます。
対して、次の最長一致パターンは内容をテキストノードに限定しているので、タグを乗り越える危険性はありません。

<class><name>[^<]*</name></class>

既存の正規表現を書き換える場合、次のような性質の違いがあります。

  • 最短一致は後続パターンが変わる度に見直さなければならない(最短一致の挙動が変わってしまう)
  • 最長一致は後続パターンが変わっても、バックトラックが発生しない限りは見直す必要がない
  • 絶対最大指定子はバックトラックが発生しないので、後続パターンが変わっても見直す必要がない

この性質の違いから、最短一致はメンテナンス性が低いと思います。

 更新履歴

  • 2017/11/03 17:43 「最短一致の問題点」の説明追記

Re: travel_saki さん

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/30 23:09

    名指しで指名するのも問題なので名前は控えますが、本回答に [高評価] を投じた後で [無評価] に戻した方がいらっしゃいます。
    回答内容に問題があったのであれば改善したいと思いますので、何か指摘を貰えると嬉しいです。

    キャンセル

  • 2017/10/30 23:18

    回答ありがとうございます。
    なるほど、最短一致だけではなく最長一致でも同じような流れができるんですね
    バックトラックに関しては初めて聞きました。。。

    すみません。追加の質問になってしまうのですが、実際に実装するとして最短一致などを用いて「<name>A</name>」を取り出した後に、残りの「<name>B</name>」と「<name>C</name>」を取り出す際にどのように実装すればいいのかイメージがまだできていないので教えて頂けませんか?

    キャンセル

  • 2017/10/30 23:38

    下記URLが参考になるでしょうか。
    http://d.hatena.ne.jp/sleepy_yoshi/20071020/

    キャンセル

  • 2017/10/30 23:51

    すごく参考になります
    実装して試してみますね!ありがとうございました!

    キャンセル

  • 2017/10/31 01:26

    >本回答に [高評価] を投じた後で [無評価] に戻した方がいらっしゃいます。
    あれ、これ僕ですかね。
    プラスが押せる状態になってるので僕っぽいですね。
    間違ってマイナスを押しちゃったみたいで、他意はないです。
    元に戻しておきました。

    キャンセル

  • 2017/10/31 04:05

    最短一致の"<name>.*?</name>"と最長一致の"<name>[^<]*</name>"とを比べてみましたが、有意な差は見えませんでした。
    →https://ideone.com/vzRwsX

    キャンセル

  • 2017/11/03 00:24

    今気付きました。
    わざわざ速度とかまで調べて頂いてありがとうございます。
    確かに見た感じ有意な差はなさそうですね。

    参考にさせて頂きます。(╹◡╹)

    キャンセル

  • 2017/11/03 11:50 編集

    To: swordone さん、travel_saki さん
    速度差はバックトラック回数に比例しています。
    name要素が3個なら「最長一致: 0回、最短一致: 3回(2+1+0)」の差になりますが、name要素が1000個なら「最長一致: 0回、最短一致: 499500回」なので、差が開くと思われます。
    (ideoneではtimeoutしてしまうようですが)
    https://ideone.com/KIeWhi
    「1 -> 2 -> 4 -> 8」のように要素の数を増やしながら差を比較すれば、最長一致の作業完了時間の上がり方が最短一致よりも緩やかな事が確認できるはずで、要素の数が何個以上なら有意な差が生まれる、なんて検証も出来ると思います。

    キャンセル

  • 2017/11/03 12:20

    To: root_jp さん
    返答ありがとうございます。
    私が見たのは root_jp さんで間違いありません。
    Javaは専門外なので不安がありましたが、何もないと知って安心しました。

    キャンセル

  • 2017/11/03 17:46

    親記事に追記しました。
    最長一致の利点はメンテナンス性にあると私は思います。

    キャンセル

0

*だけだと「最長一致数量子」といい、マッチする中で最も長い部分にマッチしようとします。
今はタグに挟まれた最短部分がほしいので、「最短一致数量子」にする必要があります。*の後に?を付けてください。

Pattern p = Pattern.compile("<name>.*?</name>");

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/30 23:06

    回答ありがとうございます。
    なるほど、そのような違いがあるのですね
    もう少し詳しく調べてみます。ありがとうございます!

    キャンセル

0

<name>.*</name>だと<name>で始まって、その後はずっと何でも良くて、</name>で終わる。
ということになるので、最初の<name>から最後の</name>がひと塊でヒットするんですね。

こういう場合は最短マッチという方法でマッチすると希望通りになるかもしれません。
<name>.*?</name>という正規表現になります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/30 23:09

    回答ありがとうございます。
    一つ文字が追加されるだけでそんな違いがあるんですね
    早速、明日実装してみます!

    キャンセル

同じタグがついた質問を見る

  • Java

    14419questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • 正規表現

    830questions

    正規表現とは特定の文字列によるパターンマッチングを行う際に用いられる宣言型プログラミングです。

  • XML

    691questions

    XMLは仕様の1つで、マークアップ言語群を構築するために使われています。