PHP - рекурсивный акроним словосочетания «PHP: Hypertext Preprocessor» Создать сайт
php
 FAQFAQ   ПоискПоиск   ПользователиПользователи   ГруппыГруппы   ПрофильПрофиль   Войти и проверить личные сообщенияВойти и проверить личные сообщения   ВходВход   РегистрацияРегистрация 

Парсинг HTML таблицы, что я делаю не так?

 
Начать новую тему   Ответить на тему    Список форумов PHP.RU -> Регулярные выражения
Предыдущая тема :: Следующая тема  
Автор Сообщение
VolCh



Зарегистрирован: 07.07.2008
Сообщения: 2

СообщениеДобавлено: Пн Июл 07, 2008 05:57    Заголовок сообщения: Парсинг HTML таблицы, что я делаю не так? Ответить с цитатой

В сотый, наверное, раз за 8 лет пытаюсь освоить регулярки, и в сотый раз не понимаю ни черта на php.net, хоть и по-русски теперь написано (когда-то со словарем переводил).


PHP:
  1.  $str='<body>text<table><tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr></table>text</body>';
  2.  $pattern='/<table>(<tr>(<td>(.*?)<\/td>)*?<\/tr>)*?<\/table>/';
  3.  
  4.  preg_match_all($pattern,$str,$matches,PREG_SET_ORDER);
  5.  
  6.  print_r ($matches);

По задумке моей должен вывести хоть как-то в $matches 1,2,3,4, причем в двухмерном виде
Выводит
PHP:
  1.  Array
  2.  (
  3.      [0] => Array
  4.          (
  5.              [0] => <table><tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr></table>
  6.              [1] => <tr><td>3</td><td>4</td></tr>
  7.              [2] => <td>4</td>
  8.              [3] => 4
  9.          )
  10.  
  11.  )

то есть выводит только последнее найденное.
Собственно, что я делаю не так? Нужно получить в итоге двумерный массив ((1,2),(3,4)) (естественно если таблица 10х10 будет, то и массив 10х10 регулярка должна создавать). Интересует именно использование регулярок, а точнее одного регулярного выражения, а потом простая ""конвертация" в итоговый массив. Всякими другими способами задачу решить могу, например через XSLT :) Да и с регулярками рекурсивно их "натравливая" могу, чтобы вырезать сначала table, потом tr, потом td, а вот чтобы одной никак :( Подскажите, пожалуйста, как сделать одной. Переносы строк, регистры и прочее не нужно учитывать, с этим разберусь, мне бы принцип понять.
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Google
Помошник


Только для не зарегистрированных пользователей
Ti



Зарегистрирован: 03.07.2006
Сообщения: 2346
Откуда: d1.ru, Екатеринбург

СообщениеДобавлено: Пн Июл 07, 2008 08:35    Заголовок сообщения: Ответить с цитатой

Итак, что Вы делаете не так:

1. preg_match_all ищет все соответствия регулярному выражению в $str (в отличии preg_match который найдет только первое)
В вашем случае всему шаблону соответствует целая таблица - результатом может быть много таблиц, а не 10x10 одной таблицы.

2. RegExp выражение никак не влияет на многомерность результата.
Массив будет или одномерный (preg_match) или двумерный (preg_match_all)

3. выражение (.)* в результате всегда будет представленно одим элеменом, а не множеством совпадений
PHP:
  1.  <?
  2.  preg_match('#(.)*#', 'text text text', $matches);
  3.  array('text text text', 't'); // результат - только первое соответствие подвыражению - 't'
  4.  array('t', 'e', 'x', 't', ' ', 't', 'e', 'x', 't') // не ждите что то вроди этого


В итоге, получить одним регулярным выражением "в итоге двумерный массив ((1,2),(3,4))" нелья.


Решение в лоб:
1. получаем таблицу
2. получаем строки таблицы
3. получаем значения


При условии что в $str одна таблица можно получить результат одним регулярным выражением с небольшими телодвижениями:
PHP:
  1.  <?
  2.  $str='<body>text<table><tr><td>1</td><td>2</td></tr><tr><td>3</td><td>4</td></tr></table>text</body>';
  3.  $pattern = '#(<tr>)?<td>(.*?)</td>#';
  4.  preg_match_all($pattern,$str,$matches);
  5.  
  6.  // $matches
  7.  array(
  8.    0 =>
  9.    array (
  10.      0 => '<tr><td>1</td>',
  11.      1 => '<td>2</td>',
  12.      2 => '<tr><td>3</td>',
  13.      3 => '<td>4</td>',
  14.    ),
  15.    1 =>
  16.    array (
  17.      0 => '<tr>',
  18.      1 => '',
  19.      2 => '<tr>',
  20.      3 => '',
  21.    ),
  22.    2 =>
  23.    array (
  24.      0 => '1',
  25.      1 => '2',
  26.      2 => '3',
  27.      3 => '4',
  28.    ),
  29.  )
  30.  // теперь есть все данные. Собираем конечный многомерный массив
  31.  // те самые телодвижения:
  32.  $i = -1;
  33.  $result = array();
  34.  foreach($matches[2] as $key=>$value) {
  35.    if ($matches[1][$key]) $i++; // если был <tr> -- новая строка таблицы
  36.    $result[$i][] = $value;
  37.  }
  38.  
  39.  // $result
  40.  array (
  41.    array ('1','2'),
  42.    array ('3','4'),
  43.  );

_________________
этой подписи здесь нет!
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
VolCh



Зарегистрирован: 07.07.2008
Сообщения: 2

СообщениеДобавлено: Пн Июл 07, 2008 19:29    Заголовок сообщения: Ответить с цитатой

Ti писал(а):
1. preg_match_all ищет все соответствия регулярному выражению в $str (в отличии preg_match который найдет только первое)
В вашем случае всему шаблону соответствует целая таблица - результатом может быть много таблиц, а не 10x10 одной таблицы.

2. RegExp выражение никак не влияет на многомерность результата.
Массив будет или одномерный (preg_match) или двумерный (preg_match_all)

Первое уже понял, а вот второе надеялся, что поддерживается многомерность, то есть вложенные скобки при повторяющихся частях будут разворачиваться в двумерный массив какой-то для каждого повторения
Ti писал(а):
Решение в лоб:
1. получаем таблицу
2. получаем строки таблицы
3. получаем значения

Первое что в голову пришло, думал, что красивее можно сделать (хотя Ваш код красивый и его использую сейчас же, если можно) - похоже, что переоценивал регулярные выражения и обычная практика для "универсального" парсера: сначала выбираем общий блок в котором есть повторяющиеся элементы (при этом неповторяющиеся, например, название статьи, можем сразу запомнить), а потом последовательно уточняем (углубляем) повторяющиеся (например, отдельные абзацы), выбирая из уже выбранного (и запомненного средствами PHP).
Вернуться к началу
Посмотреть профиль Отправить личное сообщение Посетить сайт автора
Показать сообщения:   
Начать новую тему   Ответить на тему    Список форумов PHP.RU -> Регулярные выражения Часовой пояс: GMT + 3
Страница 1 из 1

 
Перейти:  
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах


Последние пять забаневших себя:

[03.09.2010 17:11] Anonymous пустил себе кровь. Успел замарать форум 16777086 раз
[03.09.2010 16:50] Anonymous решил больше не терроризировать местную деревушку. Успел замарать форум 16777086 раз
[03.09.2010 15:01] Gromo обиделся и забанил себя на смерть. Успел замарать форум 102 раза
[03.09.2010 10:53] Anonymous бьется головой ап стену в надежде что его забанят. Успел замарать форум 16777086 раз
[03.09.2010 00:12] Anonymous ушел в кругосветку. Успел замарать форум 16777086 раз

Со 2 апреля сервис "Забанить себя" будет платным. Успейте забанить себя сегодня!

Powered by phpBB © 2001, 2005 phpBB Group
Русская поддержка phpBB

  Engine MnoGoSearch 2007-2010 © PHP.RU Powered by ODware 440Hz