• ベストアンサー

正規表現

Java 5.1 java.util.regex.Pattern java.util.regex.Matcher を用いてHTMLのTABLEを抽出したいのですが、ヒットしません。正規表現のパターンはどうしたらいいのでしょう? パターン: < *table.*?>[\s.]*?< */table *?> 検索対象: … <table border=1 width=200> <tr><th>AA</th><th>BB</th></tr> <tr><td>CC</td><td>DD</td></tr> <tr><td>EE</td><td>FF</td></tr> </table> … で、TABLEタグを含むTABLE全体を期待したのですが全くヒットしませんでした。 ちなみに * <table …>と</table>単体ではヒットします。 * ソースから改行文字を取り除いて一行テキストとした場合にはヒットします。 これらのことから、改行文字がマッチしていないことが原因かと思うのですが、パターンの正規表現についてご教授願います。

  • Java
  • 回答数5
  • ありがとう数4

質問者が選んだベストアンサー

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.5

納得していただけたようでうれしいです。 > 全ての文字か \s に含まれる文字のいずれかのくり返しというのをあらわすのに > (?:.|\s)*? > \p{javaDefined}*? >よりもスマートな表し方は思い当たりますか? 結局のところ、改行を始めとした空白文字(\s)をすべて含んだ 任意の文字を、DOTALLなしでということですよね? であれば、 [\s\S] なんてのができます。 冗談のようなパターンですが、ちゃんとお望みの文字群に マッチすると思います。

luckymako
質問者

お礼

なるほど空白文字と空白文字以外の文字ですべての文字ですか、 一見、矛盾しているかのようで、無駄が無く、感心します。 少しトリッキーなところがまた楽しませてくれます。 [\s\S]、使わせて頂きます。 何度も回答を頂き、ありがとうございました。 大変良い勉強になりました。

その他の回答 (4)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.4

> * 私が質問で書いたパターンには \S と . ドットが[ ]の中に書いてあります。 > * 質問の時点ではDOTALLを適用していません。 > 続いて同様のパターン、検索対象でDOTALLを適用して再度試みたところ成功しました。 > この時点で[ ]の中身には \s と . の両方が含まれて居ますが、 ここなのですが、ブラケット([])の中では、ほとんどのメタキャラクタは その特殊な意味を失います。 それは '.'も同じです。ブラケットの中では 任意の一キャラクタではなく、単なるピリオドにしかなりません。 ですから import java.lang.*; import java.util.regex.*; class Regtest { public static void main(String[] args) { Pattern p = Pattern.compile("[\\s.]+", Pattern.DOTALL); Matcher m = p.matcher(" . aaa \nd..ef \rxyz"); while (m.find()) { System.out.println("'" + m.group() + "'"); } } } こういうプログラムで実験してみると、 >javac -version Regtest.java javac 1.5.0_10 >java Regtest ' . ' ' ' '..' ' のような結果になり、上記の説明通りになっていることが わかります。 先の回答にも書きましたが、このようになりますので [ \s . ] は、空白(とされる文字群)かピリオドにマッチするものであり、 任意の文字ではありません。 可能ならマッチを行う部分を切り出して提示してもらえませんか? 再現できる同等のコードでもかまいません。 ref. Pattern (Java 2 Platform SE 5.0) http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/util/regex/Pattern.html 実際には、異なるメタキャラクタのセットは、文字クラスの外部ではなく内部に存在することに留意してください。たとえば、正規表現 . は、文字クラス内部ではその特殊な意味を失いますが、表現 - は範囲を示すメタキャラクタになります。 1.4の対応する部分にはこの説明はありませんが、 動作は1.4→1.5で変ってはいないはずです。

luckymako
質問者

補足

たびたびありがとうございます。 >ここなのですが、ブラケット([])の中では、ほとんどのメタキャラクタは >その特殊な意味を失います。 >それは '.'も同じです。ブラケットの中では >任意の一キャラクタではなく、単なるピリオドにしかなりません。 ドットは[ ]の中では特殊な意味を失う...驚きです。 これまでの検証で[ ]の中のドットが、すべての文字をあらわすからこそ、タグ以外の部分にマッチしていると思い込んでいました...。 お恥ずかしい限りです。 これで問題が一気に解決すると思います。 パターンを (< *table.*?>)[\s.]*?< */table *?> としてDOTALL適用しgroup(1)を出力したところ。 <table border=1 width=200> <tr><th>AA</th><th>BB</th></tr> <tr><td>CC</td><td>DD</td></tr> <tr><td>EE</td><td>FF</td></tr> が出力され、tableタグのオプション用に書いた.*?が効きすぎて全体とマッチしていたことがわかりました。 教えていただいたことを踏まえてパターンを考え直し、 < *?table[^<]*?>(?:.|\s)*?< *?/table[^<]*?> としたところ、DOTALLを適用しなくとも期待する結果を得ることができました。 ちなみに質問に回帰するのですが、 全ての文字か \s に含まれる文字のいずれかのくり返しというのをあらわすのに (?:.|\s)*? \p{javaDefined}*? よりもスマートな表し方は思い当たりますか?

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.3

正規表現を読み間違えていたのでその訂正から、 [ \s . ] (わかりやすくするために余計な空白を入れています) とあったとき、これは空白文字かピリオドにマッチします。 ですので、Pattern.DOTALLで質問にあるマッチが成功するようになったというのは おかしな話です。 確かに \s には改行(\n \r)は含まれます。 が、上で述べたように状況がちょっと不明確なところがありますので、 ・本当にDOTALLフラグをつけたことで<table>から</table>までのテキストが取れるようになったのか ・質問にある正規表現に写し間違いなどはないか の補足をお願いします。

luckymako
質問者

補足

自分の質問を読み返してるとドットが見えにくいですね... すみません。 >本当にDOTALLフラグをつけたことで<table>から</table>までのテキストが取れるようになったのか tableタグを含む文字列にマッチするようになりました。 >質問にある正規表現に写し間違いなどはないか コピーペーストですので恐らく大丈夫です。しかし、制御文字、改行文字などの不可読文字はコピーペーストや、質問投稿の間では変わっている可能性も有ります。 ちなみに質問にかいたパターン、検索対象をコピーペーストで戻して実行しても結果に差異はありませんでした。 以下は状況確認です。 * 私が質問で書いたパターンには \S と . ドットが[ ]の中に書いてあります。 * 質問の時点ではDOTALLを適用していません。 ここでフラグを何も適用しない(DOTALLを適用しない)ので 「ドットは行末記号以外の文字が対象」ということで改行は含まれず、改行文字が含まれる \s も含めました。 この指定で「可読文字」といくつかの「特殊な文字」、「改行」の繰り替えしにマッチするということになると思います。 しかし、予想とは裏腹にマッチしませんでした。 続いて同様のパターン、検索対象でDOTALLを適用して再度試みたところ成功しました。 この時点で[ ]の中身には \s と . の両方が含まれて居ますが、ドットを全ての文字(行末記号を含む)としてみなすという意味のDOTALLを適用したので . のみでも事足りて \s は無意味になっています。 タグの間を [ \s . ]から . *? (ここでの空白文字は実際にはありまえん) に置き換えてDOTALL適用有り無し夫々で夫々実行しましたが結果に差異はありません。 つまり、DOTALLを適用したことでtableタグの間にどんな文字(制御文字、改行文字など)があってもヒットするようになったということです。 これらから単なる[ . ]と[ \s ]の両者には含まれずDOTALL適用をした後の[ . ]に含まれる何らかの文字があるためにマッチしないという結論に至ったわけです。 というわけでその何らかの文字が何であるか、その文字を表す方法は何かということが質問です。

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.2

エスケープ文字、ですか? 改行コードを表すのは '\n' ですけど [\s.]*? を [\s\n.]*? とするとかいう話でしょうか?

luckymako
質問者

お礼

回答ありがとうございます。 ドキュメントを見ると、\s には[ \t\n\x0B\f\r]らが含まれているので単に改行文字だけならヒットするはずなのです...なぜという感じで... ちなみに \n \r \s \p{Cntrl} \p{Space} \p{javaWhitespace} \p{javaSpaceChar} \p{javaISOControl} \p{Cf} \p{Cc} \p{Zl} 等を、[エスケープ文字...文字クラス...]*? と書き連ねて試したのですがだめでした。 \p{javaDefined} を試した場合にはヒットしたのでJavaで定義されている何らかの文字が邪魔をしていて、探索方法(行単位に分けて探索している)などの問題でヒットしないわけではない。というところまでは分かったのですが、その文字が何なのかまではつかめていません。

luckymako
質問者

補足

お礼が補足になってなかったので追記します。 おそらく同じ事で悩んだ方がいると思いまして、解決されていればその文字コード、エスケープ文字、など教えていただきたいということです。

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.1

Patternオブジェクトを生成するときにPattern.DOTALLを追加してください。 これで '.' が改行にもマッチするようになります。

luckymako
質問者

お礼

ありがとうございます。Pattern.DOTALLでマッチしました。 ドキュメントを見るとエスケープ文字で改行などを指定できるとありますが、エスケープ文字で対応する場合には何を書けばいいのでしょうか?

関連するQ&A

  • Java正規表現-"ある文字列"を含まない文字列

    Javaの正規表現で、HTMLタグ以外の文字列を抽出しようとしています。 HTMLタグはの正規表現は"(</?.*>)"のように表しました。これの否定をしたいのですが、方法を教えて下さい。HTMLタグ以外にヒットさせたいです。 一応、現段階のソースを載せます。 import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; public class HTMLInnerGetter { public static void main(String[] args){ String regex = "(</?.*>)"; String target = "<html><head><title>title</title></head><body><h1>head1<br><p>pragraph</p></body></html>"; ArrayList<String> innerHTMLs = new ArrayList<String>(); Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(target); while(matcher.find()){ innerHTMLs.add(matcher.group(1)); } System.out.println(innerHTMLs); } } 出力結果 [<html><head><title>title</title></head><body><h1>head1<br><p>pragraph</p></body></html>] ※否定できなかったので、HTMLタグがヒットしています。

    • ベストアンサー
    • Java
  • 正規表現を使った小数入力チェック方法について

    Javaのjava.util.regex.Matcherクラスと java.util.regex.Patternクラスを使用して正規表現を使った 数値の入力チェックを行いたいと思っています。 行いたいチェックは下記の通りです。 【内容】 整数5桁以内で入力 小数部は1桁、ただし小数部は任意入力 例: 1234 => OK 12345 => OK 123456 => NG 12345. => NG 12345.1 => OK 12345.12 => NG 色々考えてみましたが 小数部が任意入力の事もあり、 うまく実現できずに困っています。 このような場合どのような正規表現を組めば良いでしょうか? よろしくお願いします。

    • ベストアンサー
    • Java
  • javaで正規表現ができません

    import java.util.regex;がよみこめません。 なので正規表現ができないみたいなのですが どうしたらうまくいくかおしえてください。 ちなみにjavaのバージョンは多分1.4.0だと思われます。。

    • ベストアンサー
    • Java
  • 1文字以上のアルファベットが入力されているかチェックするには

    正規表現で1文字以上のアルファベットが含まれているかを確認する事はできますか? 1234567890 → × a123456789 → ○ 1234a56789 → ○ 123456789a → ○ a123b4567c → ○ import java.util.regex.*; Pattern pattern = Pattern.compile("?a-zA-Z{1,}?"); Matcher matcher = pattern.matcher("文字列"); if(matcher.matches()==false){   return "NG"; } アドバイス宜しくお願いします。

    • ベストアンサー
    • Java
  • 外部ファイルに書いた正規表現を読み込んでマッチさせたい

    趣味の延長でJavaの勉強を始めたプログラミング初心者です。 開発環境は All-In-One Eclipse 3.0.1 + PropertiesEditor を使用しています。 ・やりたいこと 一つのフォルダに収められた、サイズが不定で、連番のファイル名が付けられた数百のHTMLファイルから、 外部ファイルに書いた正規表現を用いて複数の文字列を抜き出し、txtファイルにタブ区切りで書き込みたい。 ・質問 1. 「不正なインデックスを使って配列がアクセスされたことを示し」ているエラーの解決方法を教えて頂きたいです。   ソースコードの Pattern _d = Pattern.compile(_i); に正規表現を直接書くとエラーは出ませんが、   抜き出した文字列がregexp.propertiesのキーの数だけ書き込まれてしまいます。 2. 対象のフォルダはzip形式で圧縮してありますが、解凍後のサイズは数百MBもあり、これを複数処理・保存する必要があります。   そのためzip形式で圧縮したものに対して解凍せずに処理を行いたいのですが、その様な方法はあればご教示願います。 ・ソースコードと外部ファイル http://uploadr.net/file/c8f927ac3c お手数ですがこちらをご覧下さい。 ・エラー表示 Exception in thread "main" java.lang.IndexOutOfBoundsException: No group 1 at java.util.regex.Matcher.group(Unknown Source) at java.util.regex.Matcher.appendReplacement(Unknown Source) at java.util.regex.Matcher.replaceAll(Unknown Source) at goo.FileReadAndSearch.RaS(FileReadAndSearch.java:40) at goo.FileReadAndSearch.main(FileReadAndSearch.java:13) 以上です。どうぞよろしくお願い致します。

    • ベストアンサー
    • Java
  • 正規表現について

    現在下記のように文字列をチェックする正規表現を作成したのですが、 「禁止文字を含まない」と表示されてしまいます。 どこが問題なのか、指摘していただければと思います。 よろしくお願いします ---------------------------------------------------- // チェックする文字列 String str = "abc\"; // 禁止文字 String regex = "\\/:;\\*?'\"<>\\|~\\\\" + "アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨワヲンァィゥェォッャュョ゛゜ー、。「」・" + "(1)(2)(3)(4)(5)(6)(7)(8)(10)(11)(12)(13)(14)(15)(16)(17)(18)(19)(20)" + "IIIIIIIVVVIVIIVIIIIXXiiiiiiivvviviiviiiixx" + "ミリキロセンチメートルグラムトンアールヘクタールリットルワットカロリードルセントパーセントミリバールページmmcmkmmgkgccm2" + "〝〟No.K.K.TEL(上)(中)(下)(左)(右)(株)(有)(代)明治大正昭和平成∮∑∟⊿"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(str); // if (m.find()){ out.println("禁止文字を含む"); }else{ out.println("禁止文字を含まない"); }

    • ベストアンサー
    • Java
  • java正規表現 matchesがおかしい(バージョンの違い?)

    java正規表現 matchesがおかしい(バージョンの違い?) 正規表現を学びだしたところなのですが、patternのmatchesが上手くいきません。 このページ http://www.site-cooler.com/java/j2se/regex.htm に書かれている、 Pattern pattern = Pattern.compile("^Hello"); Matcher matcher = pattern.matcher("Hello World. This is regex sample."); boolean blnMatch= matcher.matches(); System.out.println(blnMatch); を実行してもfalseが返ってきてしまいます。 これはバージョンの違いからくるものなのでしょうか? ちなみに私はjre1.6でeclipse3.5を使用しています。 回答をよろしくお願いします。

    • ベストアンサー
    • Java
  • URL\正規表現@java

    perlメモさん?にPerlでのURLの正規表現はあるのですが Javaで使いたいと思います。 Pattern pattern = Pattern.compile("正規表現"); Matcher matcher = pattern.matcher(String); のステートメントを使う方法をご存知な方おられませんか? Perlメモさん?の正規表現をエディタにコピペしても 不正なエスケープエラー?がでてだめでした。 (http Urlのごちゃごちゃした奴の下から二番目) (「\b(?:」で始まる奴です) なのでエディタに貼り付けて\を\\に置き換えたものを 正規表現の部分にしたところコンパイルはとおりましたが、 正確にマッチしてくれませんでした。 よろしくお願いします。

    • ベストアンサー
    • Java
  • 正規表現の表現方法について

    じゃんけんの手を正規表現での表現方法について。 それぞれの手を定数で表現しています。場にじゃんけんの手が012と出たときに並び替えた120や210もパターン認識させたいと考えています。 正規表現の記述について教えていただきたいです。 現在のコード package game; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Test { // ユーザーの手を格納する変数 private static int playerhand; private static int user1hand; private static int user2hand; // 各々の勝数 private static int playercount = 0; private static int user1count = 0; private static int user2count = 0; // ジャンケンの手を表す定数を宣言する private static final int STONE = 0; private static final int SCISSORS = 1; private static final int PAPER = 2; // 判定する文字列 private static String checkhand = null; public static void main(String[] args) { // ここでじゃんけんさせる playerhand = STONE; user1hand = PAPER; user2hand = STONE; // 判定する文字列 checkhand = String.valueOf(playerhand) + String.valueOf(user1hand) + String.valueOf(user2hand); System.out.println(checkhand); // 判定するパターンを用意 // 引き分けパターン Pattern draw = Pattern.compile("([0]&[1]&[2])|([0]&[0]&[0])|([1]&[1]&[1])|([2]&[2]&[2])"); // 2人勝ちパターン Pattern win2 = Pattern.compile("([0]&[0]&[1])|([1]&[1]&[2])|([2]&[2]&[0])"); // 1人勝ちパターン Pattern win1 = Pattern.compile("([0]&[1]&[1])|([1]&[2]&[2])|([2]&[0]&[0])"); // パターンとの一致を確認するための準備 Matcher checkdraw = draw.matcher(checkhand); Matcher checkwin2 = win2.matcher(checkhand); Matcher checkwin1 = win1.matcher(checkhand); if (checkdraw.find()) { System.out.println("引き分けパターン"); } else if (checkwin2.find()) { System.out.println("2人勝ちのパターン"); checkWin2(); } else if (checkwin1.find()) { System.out.println("1人勝ちのパターン"); checkWin1(); } } /** * 1人勝ちで勝者の勝数を増やすメソッド * */ public static void checkWin1() { if (playerhand == user1hand) { user2count++; } else if (user1hand == user2hand) { playercount++; } else { user1hand++; } } /** * 2人勝ちで勝者の勝数を増やすメソッド */ public static void checkWin2() { if (playerhand == user1hand) { playercount++; user1count++; } else if (user1hand == user2hand) { user1hand++; user2hand++; } else { playercount++; user2count++; } } } ※OKWAVEより補足:「Webシステム開発」についての質問です。

    • ベストアンサー
    • Java
  • テーブルのレイアウトがおかしくなる

    畏れ入ります。 テーブルを作っているのですが奇妙な現象にあっています。 <table border="1" width="100%"> <tr> <th width="18">&nbsp;</th> <th width="100">&nbsp;</th> <th>&nbsp;</th> <th width="100">&nbsp;</th> </tr> <tr> <td rowspan="2">&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <td colspan="3">&nbsp; <!-- ここに たくさんの 文字列を入れると ・・・ --> </td> </tr> </table> このコメントの部分が無い状態では正常にでていますが、 ここにたくさんの文字列(半角30文字程度でおかしくなります)を投入すると、レイアウトが異常に崩れてしまいます。 文字列は改行してもかまわないのですが テーブル1行目2行目のセルサイズ(width)がこのように変化してしまうと困るのです。 どのようにしたら良いか(width=100の部分を守らせたい) 教えてください。

    • ベストアンサー
    • HTML

専門家に質問してみよう