Гость
Форумы / PHP, Perl, Python [игнор отключен] [закрыт для гостей] / (php) Сферический конь в вакууме на регулярках (preg_match_all) / 7 сообщений из 7, страница 1 из 1
11.04.2020, 22:08
    #39946252
Cyrax_02
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
(php) Сферический конь в вакууме на регулярках (preg_match_all)
Пример 1 (результат корректный, ожидаемый):
Код: php
1.
2.
3.
$str = "1 <01> 2 <PP> 3";
$regexpr = '/<(?<DIGIT>\d+)>|<(?<LETTER>\w+)>/u';
preg_match_all($regexpr, $str, $matches, PREG_PATTERN_ORDER);

Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
Array
(
    [0] => Array
(
	[0] => "<01>"
	[1] => "<PP>"
        )
    [DIGIT] => Array
(
	[0] => "01"
	[1] => ""
        )
    [1] => Array
(
	[0] => "01"
	[1] => ""
        )
    [LETTER] => Array
(
	[0] => ""
	[1] => "PP"
        )
    [2] => Array
(
	[0] => ""
	[1] => "PP"
        )
)


Пример 2 (результат корректный, ожидаемый):
Код: php
1.
2.
3.
$str = "1 <01> 2 <PP> 3";
$regexpr = '/<(?<DIGIT>\d+)>|<(?<LETTER>\w+)>/u';
preg_match_all($regexpr, $str, $matches, PREG_SET_ORDER);

Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
Array
(
    [0] => Array
(
	[0] => "<01>"
	[DIGIT] => "01"
        [1] => "01"
        )
    [1] => Array
(
	[0] => "<PP>"
	[DIGIT] => ""
        [1] => ""
        [LETTER] => "PP"
        [2] => "PP"
        )
)


Пример 3 . Объединим именные карманы DIGIT и LETTER в один общий карман CHAR с помощью опции (?J)
Код: php
1.
2.
3.
$str = "1 <01> 2 <PP> 3";
$regexpr = '/(?J)<(?<CHAR>\d+)>|<(?<CHAR>\w+)>/u';
preg_match_all($regexpr, $str, $matches, PREG_SET_ORDER);

Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
Array
(
    [0] => Array
(
        [0] => "<01>"
	[CHAR] => "01"    // объединённый карман
        [1] => "01"
        )
    [1] => Array
(
	[0] => "<PP>"
	[CHAR] => "PP"    // объединённый карман
        [1] => ""         // индексные карманы НЕ объединяет, ну да и ладно (главное, объединил именные карманы)
        [2] => "PP"
        )
)


Пример 4 . Объединённый карман + PREG_PATTERN_ORDER
Код: php
1.
2.
3.
$str = "1 <01> 2 <PP> 3";
$regexpr = '/(?J)<(?<CHAR>\d+)>|<(?<CHAR>\w+)>/u';
preg_match_all($regexpr, $str, $matches, PREG_PATTERN_ORDER);

Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
Array
(
    [0] => Array
        (
            [0] => "<01>"
            [1] => "<PP>"
        )
    [CHAR] => Array
        (
            [0] => ""    // где "01" ???
            [1] => "PP"
        )
    [1] => Array
        (
            [0] => "01"
            [1] => ""
        )
    [2] => Array
        (
            [0] => ""
            [1] => "PP"
        )
)


Вот здесь мы получили сферического коня в вакууме. Исходя из логики опции (?J) , карман с ключом "CHAR" должен иметь вид ["01", "pp"], а не ["", "pp"]. Т.е. объединения именных карманов не произошло и второй карман с именем "CHAR" перезаписал первый карман с именем "CHAR".

Возможны 3 варианта :
1) Особенность "объединения" одноимённых карманов в режиме PREG_PATTERN_ORDER, которую я понять не могу
2) Bug версии php 5.6, исправленный в версии 7.x
3) Bug версии php 7.x тоже, до сих пор не исправленный

Для справки :
авторIf you are using named patterns you can now have the same name multiple times, provided you put the " (?J) " option in your pattern. For example: Match: (?J)(?P<name>Ni.+)|(?P<name>Fr.+)
This would match "Nick" or "Fred", and whichever one matched, the named pattern "name" would be set to it.
The (?J) internal option setting changes the local PCRE_DUPNAMES option. Allow duplicate names for subpatterns. As of PHP 7.2.0 J is supported as modifier as well.
...
Рейтинг: 0 / 0
14.04.2020, 15:42
    #39947018
Cyrax_02
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
(php) Сферический конь в вакууме на регулярках (preg_match_all)
Может, кто проверит в php 7.2+ регулярное выражение из примера 4 в режиме PREG_PATTERN_ORDER :
'/(?J)<(?<CHAR>\d+)>|<(?<CHAR>\w+)>/u'
...
Рейтинг: 0 / 0
14.04.2020, 16:53
    #39947057
vkle
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
(php) Сферический конь в вакууме на регулярках (preg_match_all)
Cyrax_02
Может, кто проверит в php 7.2+ регулярное выражение из примера 4 в режиме PREG_PATTERN_ORDER :
'/(?J)<(?<CHAR>\d+)>|<(?<CHAR>\w+)>/u'


PHP 7.3.16 (cli) и PHP 7.2.29 (cli) одинаково
Код: php
1.
2.
3.
4.
<?php
$str = "1 <01> 2 <PP> 3";
$regexpr = '/(?J)<(?<CHAR>\d+)>|<(?<CHAR>\w+)>/u';
preg_match_all($regexpr, $str, $matches, PREG_PATTERN_ORDER);


Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
array(4) {
  [0] =>
  array(2) {
    [0] =>
    string(4) "<01>"
    [1] =>
    string(4) "<PP>"
  }
  'CHAR' =>
  array(2) {
    [0] =>
    string(0) ""
    [1] =>
    string(2) "PP"
  }
  [1] =>
  array(2) {
    [0] =>
    string(2) "01"
    [1] =>
    string(0) ""
  }
  [2] =>
  array(2) {
    [0] =>
    string(0) ""
    [1] =>
    string(2) "PP"
  }
}
...
Рейтинг: 0 / 0
14.04.2020, 17:54
    #39947087
Cyrax_02
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
(php) Сферический конь в вакууме на регулярках (preg_match_all)
Плохи дела... Не исправили в 7.x .
vkle , если не сложно, ещё одно регулярное выражение (здесь второй "CHAR" всегда пуст => перезаписывает/очищает объединённый "CHAR"):
Код: php
1.
2.
3.
$str = "1 <01>2 <PP>3";  // здесь проблема наблюдается в обоих режимах
$re = '/(?J)(?:<(?<CHAR>\d+)>|@(?<CHAR>0+)@)(?P<END>\d+)/u';
preg_match_all($re, $str, $matches, PREG_SET_ORDER);  // PREG_PATTERN_ORDER

Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
Array
(
    [0] => Array
        (
            [0] => "<01>2"
            [CHAR] => ""
            [1] => "01"
            [2] => ""
            [END] => "2"
            [3] => "2"
        )
)


P.S. А что, если поставить опцию (?J) в конец регулярного выражения в качестве модификатора: .../u J
Не поможет?
...
Рейтинг: 0 / 0
14.04.2020, 20:03
    #39947191
vkle
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
(php) Сферический конь в вакууме на регулярках (preg_match_all)
Cyrax_02
Не исправили в 7.x .
А есть открытый багрипорт? Там, где проблема обозначена. Которую исправить надобно.

Cyrax_02
ещё одно регулярное выражение
Так именно и выводит.

Cyrax_02
Не поможет?
Без изменений
...
Рейтинг: 0 / 0
14.04.2020, 21:22
    #39947232
Cyrax_02
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
(php) Сферический конь в вакууме на регулярках (preg_match_all)
авторА есть открытый багрипорт? Там, где проблема обозначена. Которую исправить надобно.Думал, иногда исправляют без багрепортов.
На bugs.php.net таких багрепортов нет. И нафиг нужно. Работать нужно сейчас, а не через 10 лет.

Регулярные выражения с одноимёнными подмасками переписал на условные подмаски с относительными ссылками. Короче получились и, скорее всего, работать станут быстрее, т.к. не содержат полных альтернатив (только частичные).

P.S . Пример 3 на самом деле тоже глючный. Просто там пустой индексный карман оказался в самом конце, а последние пустые карманы, как известно, удаляются. Если бы там ещё карманы были, то он бы не был удалён и перезаписал (очистил) бы объединённый карман "CHAR"
...
Рейтинг: 0 / 0
23.04.2020, 14:38
    #39950503
Cyrax_02
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
(php) Сферический конь в вакууме на регулярках (preg_match_all)
Как оказалось, сабжевый багрепорт был (от 11 ферваля 2020 г.)
Встроенный поиск на bugs.php.net и поиск Яндекса с задачей не справились.

В php 7.4 проблема устранена: пустые вхождения больше не будут записываться в объединённый именной карман
http://bugs.php.net/79257 Bug #79257: Duplicate named groups (?J) prefer last alternative even if not matched
In 7.4 named capture group always returns the content captured in last alternative , no matter which of the alternatives matched.

Looks like the actual problem existed in 7.3 and earlier , but it required slight modification to be reproduced. I'll try to update the bug report to take it into account.

I've fixed this in PHP-7.4 . I don't want to fix this on 7.3. It's a long standing issue, and changes to PCRE matches output are risky.
...
Рейтинг: 0 / 0
Форумы / PHP, Perl, Python [игнор отключен] [закрыт для гостей] / (php) Сферический конь в вакууме на регулярках (preg_match_all) / 7 сообщений из 7, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]