Ошибка РНР в регулярных выражениях :(

Роберт

Аналитик
Ошибка РНР в регулярных выражениях :(

У меня РНР версии 5.0.5 и 5.1.2 (модули , Windows)
Может кто-нибудь проверить в своих версиях - возникает ли такая же самая ошибка?

PHP:
<?
$a1="\r\n\r\n";
$a2="\r\n\r\n1";
preg_match('#(.+?)$#s',$a1,$r1);
preg_match('#(.+?)$#s',$a2,$r2);
echo strlen($r1[1]).'<br>';
echo strlen($r2[1]).'<br>';
?>
у меня выдаётся результат 3 и 5 (хотя должен 4 и 5).

Тоесть получается что РНР в случае поиска до конца переменной игнорирует последний \n если переменна в которой производится поиск заканчивается на \r\n

При этом - жадный preg_match('#(.+)#s',$a1,$r1); вернёт как положено - 4

За что они так возненавидили виндоуский Enter?

Подтвердите если и у вас получается такая же ошибка , будем писать разработчикам...
 

zarus

Хитрожопый макак
А собственно, где баг?
preg_match('#(.+?)$#s',"\r\n\r\n",$r1);
Последний перенос строки считается концом строки, если после него нет символов (что в общем-то логично), и на этом процесс поиска останавливается...

Даже если это и баг - то явно не PHP. Regex Coach (ну он-то не на PHP написан) выдает те же 3 символа при таком условии.
 

Роберт

Аналитик
zarus
> перенос строки считается концом строки, если после него нет символов
Если бы было так как ты говоришь , то "\n" имел бы нулевую динну.
А так и "\n" , и "\n\n" имеют одинаковую длинну - 1
И разве не баг что каждый запрос до конца переменной уменьшает мне количество строк на единицу?

Ну допустим формат файла - "Заголовк\nТема\n\nДанные\n\n\n". Где темы и данные могут повторяться , типа:
Заголовк
Тема
Данные
Данные
Тема
Данные
Тема
Данные
Данные
Данные
- для простой выборки данных подойдёт
PHP:
preg_match('#([^\n].+?)\n\n\n#s',$r1);
Но если я перед этим делал выборки с использованием "не жадного до конца переменной" , выделяя блоки с Заголовками или Темами , то последнюю запись с Данными я уже не найду , так как при каждой выборке у меня будет пропадать последняя строка...
 

zarus

Хитрожопый макак
Автор оригинала: Роберт
PHP:
preg_match('#([^\n].+?)\n\n\n#s',$r1);
Но если я перед этим делал выборки с использованием "не жадного до конца переменной" , выделяя блоки с Заголовками или Темами , то последнюю запись с Данными я уже не найду, так как при каждой выборке у меня будет пропадать последняя строка...
Чушь - с чего бы вдруг не пустая строка должна пропадать? А пустая никому не нужна. Прежде чем делать заявление, может, стоит проверить, что оно имеет место?
Сдается мне, Вы не до конца понимаете смысл нежадного и жадного поиска:
Жадный поиск ищет максимальную строку, отвечающую заданному паттерну.
Нежадный останавливается после первого удачного вхождения.

-~{}~ 18.01.06 09:57:

Тестовая строка:
"Заголовк
Тема

Данные


Да
Да
"
Пример 1 (Жадный поиск на конце паттерна):
([^\s].*?)\n\n([^\s].*?)\n([^\s].*)

Пример 2 (Нежадный поиск на конце паттерна):
([^\s].*?)\n\n([^\s].*?)\n([^\s].*?)

Пример 3 (Нежадный поиск на конце паттерна с условием соответствия концу строки):
([^\s].*?)\n\n([^\s].*?)\n([^\s].*?)$
 

Роберт

Аналитик
zarus
> Чушь - с чего бы вдруг не пустая строка должна пропадать?
Не пустая и не может пропасть! Я говорю о строке состоящей из одного символа \n

>А пустая никому не нужна.
Вот тут я и не согласен! Если строка есть - то она НЕ должна пропадать! А то с таким же успехом можно заявить что и пробел на конце строки никому не нужен!!!

>Сдается мне, Вы не до конца понимаете смысл нежадного и жадного поиска:
За это можешь не бояться - 6 лет с ними работаю...

>Тестовая строка:
Вот тут ты допустил небольшую неточность. Если после строк "Да" стоит один \n - значит это Заголовки , если \n\n - тогда Тема , а если \n\n\n - тогда Данные. И в данном случае - обе строки "Да" - заголовки.
Но допустим мы сделаем их данными:
"Заголовк
Тема

Данные


Да


Да


"
В этом случае если я сделю нежадный запрос по темам:
начиная от темы до (темы или конца строки)
То в моей выборке окажутся Тема , и все Данные которые относятся к этой теме:
"Тема

Данные


Да


Да

"
Заметил что произошло? Последнее "Да" стало темой , потому что preg вернув мне "всё до конца строки" на самом деле не вернул мне последнего \n (в результате у меня на одну строку стало меньше). И если к этому результату прменить ещё один запрос типа "#(.............+?)$#s" , то он уничтожит и последнюю строку , тем самым переведя последнее "Да" в разряд Заголовков.
 

zarus

Хитрожопый макак
PHP:
$test_string = "Theme1\nHeader1.1\n\nData1.1.1\n\n\nData1.1.2\n\n\n"
              ."Theme2\nHeader2.1\n\nData2.1.1\n\n\nData2.1.2\n\n\nHeader2.2\n\nData2.2.1\n\n\n";
              
$new_theme_set = array(
               'theme'   => '',
             );
$data_set = array();
$header_set = array();
$theme_set = array();
$max_len = count($test_string);
$i = 0;
$data_set = explode("\n\n\n",$test_string);
print_r($data_set);
echo '<hr />';
$theme_breaker = array();
$header_breaker = array();
function increase_by_one(&$item,$key,$offset) {
  if ($item) {
    $item = $item < $offset ? $item : $item + 1;
  } else {
    $item = 1;
  }
}
function find_data(&$data_set,$delim) {
  foreach ($data_set as $k1 => $d1) {
    if (trim($d1) == '') {
      unset($data_set[$k1]);
    }
    $temp2 = explode($delim,$d1);
    if (count($temp2) > 1) {
      $tmp1 = array_slice($data_set,0,$k1);
      $tmp2 = array_slice($data_set,$k1+1);
      $data_set = array_merge($tmp1,$temp2,$tmp2);
      return $k1;
    }
  }
  return false;
}
$cnt = 0;
while (false !== ($breaker = find_data($data_set,"\n\n"))) {
  $header_breaker[] = $breaker;
}
while (false !== ($breaker = find_data($data_set,"\n"))) {
  array_walk($header_breaker,'increase_by_one',$breaker);
  $theme_breaker[] = $breaker;
}
foreach ($data_set as $key => $value) {
  if (in_array($key,$theme_breaker)) {
    $theme_set[] = $new_theme_set;
    $pos = count($theme_set)-1;
    $theme_set[$pos]['theme'] = $value;
  } elseif (in_array($key,$header_breaker)) {
    $theme_set[$pos]['headers'][]['header'] = $value;
    $dat_pos = count($theme_set[$pos]['headers'])-1;
  } else {
    $theme_set[$pos]['headers'][$dat_pos]['data'][] = $value;
  }
}
print_r($theme_breaker);
echo '<hr />';
print_r($header_breaker);
echo '<hr />';
print_r($data_set);
echo '<hr />';
print_r($theme_set);
Может это тебе поможет...

-~{}~ 20.01.06 19:17:

И никаких регэкспов
 

Роберт

Аналитик
Ой , zarus , проблемы решить задачу нету... она действительно также легко решается и без регулярных выражений...
Просто я считал (и счиаю) что пропажа конечного символа \n при запросе до конца перенной - это ошибка!
 
Сверху