PHPのpreg_match_allで、正規表現チェッカーとEclipseの結果が異なりうまくいかなく困ってます


HTMLの<table>内の<tr><td>から必要な情報を取得したいのですが、
正規表現チェッカーでは正しい結果が 2次元配列に繰り返しで入るのですが、
Eclipseでは、全体がarray[0][0]にマッチしてしまい、array[1][0]、array[2][0]... は最終行しか取れてない状況です。

元データ

<tr class="a"><td class="b">1</td><td class="c">1</td><td class="d"><a href="test1">test1</a></td><td class="e">1</td><td class="f"><a href="test1">test1</a></td></tr>
<tr class="a"><td class="b">2</td><td class="c">2</td><td class="d"><a href="test2">test2</a></td><td class="e">2</td><td class="f"><a href="test2">test2</a></td></tr>
<tr class="a"><td class="b">3</td><td class="c">3</td><td class="d"><a href="test3">test3</a></td><td class="e">3</td><td class="f"><a href="test3">test3</a></td></tr>


正規表現

preg_match_all('@<tr.*><td.*>(.*)<\/td><td.*>(.*)<\/td><td.*>(<a.*>.*<\/a>)<\/td><td.*>(.*)<\/td><td.*>(<a.*>.*<\/a>)<\/td><\/tr>@', $html, $matches);


htmlは mb_convert_encodingでUTF-8に変更してから、改行、タブを削除してます。

どなたかわかる方いらっしゃいましたらご教授お願いします。

回答の条件
  • 1人10回まで
  • 13歳以上
  • 登録:2017/08/19 11:56:53
  • 終了:2017/08/20 14:09:53

ベストアンサー

id:a-kuma3 No.1

a-kuma3回答回数4623ベストアンサー獲得回数19582017/08/19 13:24:45

\s*(.*)\s*

の部分、こうしてみたらどうでしょう。

\s*([^<\s]*)\s*





追記です。
正規表現チェッカー云々のくだりがよく分かりませんが、「全体がarray[0][0]にマッチしてしまい」は正しい動作です。
正確には「全体が」ではなく、「ほぼ全体が」ですが。

期待している通りにならないのは、.* が強くマッチするからです。
かっこの中だけではなく、タグの属性だけを引き当てているつもりの部分も。
ひとつひとつ直した方が、後々のため(プログラムの寿命がよく分かりませんが)良いと思いますが、U フラグを使う手もあります。

<?php
    $html = '<tr class="a"><td class="b">1</td><td class="c">1</td><td class="d"><a href="test1">test1</a></td><td class="e">1</td><td class="f"><a href="test1">test1</a></td></tr><tr class="a"><td class="b">2</td><td class="c">2</td><td class="d"><a href="test2">test2</a></td><td class="e">2</td><td class="f"><a href="test2">test2</a></td></tr><tr class="a"><td class="b">3</td><td class="c">3</td><td class="d"><a href="test3">test3</a></td><td class="e">3</td><td class="f"><a href="test3">test3</a></td></tr>';
    preg_match_all('@<tr.*><td.*>(.*)<\/td><td.*>(.*)<\/td><td.*>(<a.*>.*<\/a>)<\/td><td.*>(.*)<\/td><td.*>(<a.*>.*<\/a>)<\/td><\/tr>@U', $html, $matches);
    var_dump($matches);
array(6) {
  [0]=>
  array(3) {
    [0]=>
    string(167) "<tr class="a"><td class="b">1</td><td class="c">1</td><td class="d"><a href="test1">test1</a></td><td class="e">1</td><td class="f"><a href="test1">test1</a></td></tr>"
    [1]=>
    string(167) "<tr class="a"><td class="b">2</td><td class="c">2</td><td class="d"><a href="test2">test2</a></td><td class="e">2</td><td class="f"><a href="test2">test2</a></td></tr>"
    [2]=>
    string(167) "<tr class="a"><td class="b">3</td><td class="c">3</td><td class="d"><a href="test3">test3</a></td><td class="e">3</td><td class="f"><a href="test3">test3</a></td></tr>"
  }
  [1]=>
  array(3) {
    [0]=>
    string(1) "1"
    [1]=>
    string(1) "2"
    [2]=>
    string(1) "3"
  }
  [2]=>
  array(3) {
    [0]=>
    string(1) "1"
    [1]=>
    string(1) "2"
    [2]=>
    string(1) "3"
  }
  [3]=>
  array(3) {
    [0]=>
    string(25) "<a href="test1">test1</a>"
    [1]=>
    string(25) "<a href="test2">test2</a>"
    [2]=>
    string(25) "<a href="test3">test3</a>"
  }
  [4]=>
  array(3) {
    [0]=>
    string(1) "1"
    [1]=>
    string(1) "2"
    [2]=>
    string(1) "3"
  }
  [5]=>
  array(3) {
    [0]=>
    string(25) "<a href="test1">test1</a>"
    [1]=>
    string(25) "<a href="test2">test2</a>"
    [2]=>
    string(25) "<a href="test3">test3</a>"
  }
}

http://ideone.com/z8my8G

他5件のコメントを見る
id:a-kuma3

< class="a"><td class=... で
< class="a"> にだけマッチさせたい場合には、

<tr.*>

<tr[^>]*>

<tr.*?>

というようにします。

2017/08/20 14:50:32
id:sironeko12

<tr[^>]*> という方法もあるんですね。

上記ではうまくいきませんでしたが、

同じようなものを探していたところ、以下のような方法があり、
こちらの方法だとうまくいきました。

preg_match_all('@<tr[^>]*>(.*?)<\/tr>@is', $html, $lines);

$result = array();
foreach ($lines[1] as $k => $line) {
  preg_match_all('@<td[^>]*>(.*?)<\/td>@is', $lines, $cell);

  foreach ($cell[1] as $cell) {
    $result[$k][] = trim($cell);
  }
}

いろいろご教授頂きありがとうございました。

2017/08/20 22:00:07

その他の回答(0件)

id:a-kuma3 No.1

a-kuma3回答回数4623ベストアンサー獲得回数19582017/08/19 13:24:45ここでベストアンサー

\s*(.*)\s*

の部分、こうしてみたらどうでしょう。

\s*([^<\s]*)\s*





追記です。
正規表現チェッカー云々のくだりがよく分かりませんが、「全体がarray[0][0]にマッチしてしまい」は正しい動作です。
正確には「全体が」ではなく、「ほぼ全体が」ですが。

期待している通りにならないのは、.* が強くマッチするからです。
かっこの中だけではなく、タグの属性だけを引き当てているつもりの部分も。
ひとつひとつ直した方が、後々のため(プログラムの寿命がよく分かりませんが)良いと思いますが、U フラグを使う手もあります。

<?php
    $html = '<tr class="a"><td class="b">1</td><td class="c">1</td><td class="d"><a href="test1">test1</a></td><td class="e">1</td><td class="f"><a href="test1">test1</a></td></tr><tr class="a"><td class="b">2</td><td class="c">2</td><td class="d"><a href="test2">test2</a></td><td class="e">2</td><td class="f"><a href="test2">test2</a></td></tr><tr class="a"><td class="b">3</td><td class="c">3</td><td class="d"><a href="test3">test3</a></td><td class="e">3</td><td class="f"><a href="test3">test3</a></td></tr>';
    preg_match_all('@<tr.*><td.*>(.*)<\/td><td.*>(.*)<\/td><td.*>(<a.*>.*<\/a>)<\/td><td.*>(.*)<\/td><td.*>(<a.*>.*<\/a>)<\/td><\/tr>@U', $html, $matches);
    var_dump($matches);
array(6) {
  [0]=>
  array(3) {
    [0]=>
    string(167) "<tr class="a"><td class="b">1</td><td class="c">1</td><td class="d"><a href="test1">test1</a></td><td class="e">1</td><td class="f"><a href="test1">test1</a></td></tr>"
    [1]=>
    string(167) "<tr class="a"><td class="b">2</td><td class="c">2</td><td class="d"><a href="test2">test2</a></td><td class="e">2</td><td class="f"><a href="test2">test2</a></td></tr>"
    [2]=>
    string(167) "<tr class="a"><td class="b">3</td><td class="c">3</td><td class="d"><a href="test3">test3</a></td><td class="e">3</td><td class="f"><a href="test3">test3</a></td></tr>"
  }
  [1]=>
  array(3) {
    [0]=>
    string(1) "1"
    [1]=>
    string(1) "2"
    [2]=>
    string(1) "3"
  }
  [2]=>
  array(3) {
    [0]=>
    string(1) "1"
    [1]=>
    string(1) "2"
    [2]=>
    string(1) "3"
  }
  [3]=>
  array(3) {
    [0]=>
    string(25) "<a href="test1">test1</a>"
    [1]=>
    string(25) "<a href="test2">test2</a>"
    [2]=>
    string(25) "<a href="test3">test3</a>"
  }
  [4]=>
  array(3) {
    [0]=>
    string(1) "1"
    [1]=>
    string(1) "2"
    [2]=>
    string(1) "3"
  }
  [5]=>
  array(3) {
    [0]=>
    string(25) "<a href="test1">test1</a>"
    [1]=>
    string(25) "<a href="test2">test2</a>"
    [2]=>
    string(25) "<a href="test3">test3</a>"
  }
}

http://ideone.com/z8my8G

他5件のコメントを見る
id:a-kuma3

< class="a"><td class=... で
< class="a"> にだけマッチさせたい場合には、

<tr.*>

<tr[^>]*>

<tr.*?>

というようにします。

2017/08/20 14:50:32
id:sironeko12

<tr[^>]*> という方法もあるんですね。

上記ではうまくいきませんでしたが、

同じようなものを探していたところ、以下のような方法があり、
こちらの方法だとうまくいきました。

preg_match_all('@<tr[^>]*>(.*?)<\/tr>@is', $html, $lines);

$result = array();
foreach ($lines[1] as $k => $line) {
  preg_match_all('@<td[^>]*>(.*?)<\/td>@is', $lines, $cell);

  foreach ($cell[1] as $cell) {
    $result[$k][] = trim($cell);
  }
}

いろいろご教授頂きありがとうございました。

2017/08/20 22:00:07
id:sironeko12

質問文を編集しました。詳細はこちら

コメントはまだありません

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません