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

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

新規登録して質問してみよう
ただいま回答率
85.51%
XML

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

Java

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

正規表現

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

Q&A

解決済

3回答

3009閲覧

javaの正規表現について

travel_saki

総合スコア12

XML

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

Java

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

正規表現

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

0グッド

0クリップ

投稿2017/10/30 11:48

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

xml

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

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

Java

1// 判定する文字列 2String str = "<name>A</name><name>B</name><name>C</name>"; 3 4// 判定するパターンを生成 5Pattern p = Pattern.compile("<name>.*</name>"); 6Matcher m = p.matcher(str); 7 8// 出力 9System.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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

対策は2つあります。

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

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

最長一致

Java

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

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

Java

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

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

最短一致の問題点

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

Java

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

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

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

Java

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

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

Java

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

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

Java

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

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

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

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

更新履歴

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

Re: travel_saki さん

投稿2017/10/30 12:20

編集2017/11/03 08:43
think49

総合スコア18156

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

think49

2017/10/30 14:09

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

2017/10/30 14:18

回答ありがとうございます。 なるほど、最短一致だけではなく最長一致でも同じような流れができるんですね バックトラックに関しては初めて聞きました。。。 すみません。追加の質問になってしまうのですが、実際に実装するとして最短一致などを用いて「<name>A</name>」を取り出した後に、残りの「<name>B</name>」と「<name>C</name>」を取り出す際にどのように実装すればいいのかイメージがまだできていないので教えて頂けませんか?
travel_saki

2017/10/30 14:51

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

2017/10/30 16:26

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

2017/10/30 19:05

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

2017/11/02 15:24

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

2017/11/03 02:51 編集

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」のように要素の数を増やしながら差を比較すれば、最長一致の作業完了時間の上がり方が最短一致よりも緩やかな事が確認できるはずで、要素の数が何個以上なら有意な差が生まれる、なんて検証も出来ると思います。
think49

2017/11/03 03:20

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

2017/11/03 08:46

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

0

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

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

投稿2017/10/30 11:58

root_jp

総合スコア4666

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

travel_saki

2017/10/30 14:09

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

0

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

java

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

投稿2017/10/30 11:55

swordone

総合スコア20649

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

travel_saki

2017/10/30 14:06

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問