Почему.* не использует всю строку в этом Perl regex?

C99 или ранее

стандарт C (C99) предусматривает широкие символы и многобайтовые символы, но так как нет никакой гарантии о том, что могут содержать те широкие символы, их значение несколько ограничено. Для данной реализации они оказывают полезную поддержку, но если Ваш код должен смочь переместиться между реализациями, существует недостаточная гарантия, что они будут полезны.

, Следовательно, подход, предложенный Hans van Eck (который должен записать обертку вокруг ICU - Международных Компонентов для Unicode - библиотека), является звуковым, IMO.

кодировка UTF-8 имеет много достоинств, одно из которых - то, что, если Вы не смешиваете с данными (путем усечения ее, например), затем она может быть скопирована функциями, которые не полностью осведомлены о запутанности кодировки UTF-8. Это - категорически не случай с wchar_t.

Unicode полностью является 21-разрядным форматом. Таким образом, Unicode резервирует кодовые точки от U+0000 до U+10FFFF.

Одна из полезных вещей о UTF-8, UTF-16 и форматы UTF-32 (где UTF обозначает Формат преобразования Unicode - видят Unicode) - то, что можно преобразовать между этими тремя представлениями без потери информации. Каждый может представить что-либо, что другие могут представить. И UTF-8 и UTF-16 являются многобайтовыми форматами.

UTF-8 известен быть многобайтовым форматом с осторожной структурой, которая позволяет найти запуск символов в строке надежно, запускающийся в любой точке в строке. Однобайтовые символы имеют высоко-разрядный набор для обнуления. Многобайтовые символы имеют первый символ, запускающийся с одной из комбинаций двоичных разрядов 110, 1110 или 11110 (для 2 байтов, 3-байтовых или 4-байтовых символов), с последующими байтами, всегда запускающимися 10. Символы продолжения всегда находятся в диапазоне 0x80.. 0xBF. Существуют правила, что символы UTF-8 должны быть представлены в минимальном возможном формате. Одно последствие этих правил то, что байты 0xC0 и 0xC1 (также 0xF5.. 0xFF), не может появиться в допустимых данных UTF-8.

 U+0000 ..   U+007F  1 byte   0xxx xxxx
 U+0080 ..   U+07FF  2 bytes  110x xxxx   10xx xxxx
 U+0800 ..   U+FFFF  3 bytes  1110 xxxx   10xx xxxx   10xx xxxx
U+10000 .. U+10FFFF  4 bytes  1111 0xxx   10xx xxxx   10xx xxxx   10xx xxxx

Первоначально, надеялись, что Unicode будет набором 16-битного кода, и все вписалось бы в пространство 16-битного кода. К сожалению, реальный мир более сложен, и он должен был быть расширен до текущего 21-разрядного кодирования.

UTF-16 таким образом является единым блоком (16-разрядное слово) кодовый набор для 'Основной Многоязычной Плоскости', означая символы с кодовыми точками Unicode U+0000.. U+FFFF, но использование две единицы (32 бита) для символов вне этого диапазона. Таким образом код, который работает с кодировкой UTF-16, должен смочь обработать кодировку переменной ширины, точно так же, как UTF-8 должен. Коды для символов двойной единицы называют суррогатами.

Суррогаты являются кодовыми точками от двух специальных диапазонов значений Unicode, зарезервированных для использования в качестве продвижения и запаздывающих значений парных элементов кода в UTF-16. Продвижение, также названный высоко, суррогаты от U+D800 до U+DBFF и запаздывания, или низко, суррогаты от U+DC00 до U+DFFF. Их называют суррогатами, так как они не представляют символы непосредственно, но только как пара.

UTF-32, конечно, может закодировать любую кодовую точку Unicode в едином блоке устройства хранения данных. Это эффективно для вычисления, но не для устройства хранения данных.

можно найти намного больше информации в веб-сайты Unicode и ICU.

C11 и

стандарт C11 изменил правила, но не все реализации догнали изменения даже сейчас (середина 2017). Стандарт C11 суммирует изменения для поддержки Unicode как:

  • символы Unicode и строки () (первоначально указанный в ISO/IEC TR 19769:2004)

, Что следует, являются пустой минимальной схемой функциональности. Спецификация включает:

6.4.3 Универсальных имен персонажей

Синтаксис
универсальное имя персонажа:
        \u шестнадцатеричная четверка
        \U шестнадцатерично-квадратическая шестнадцатеричная четверка
шестнадцатеричная четверка:
        шестнадцатерично-разрядный шестнадцатерично-разрядный шестнадцатерично-разрядный шестнадцатерично-разрядный

7.28 утилит Unicode

заголовок объявляет типы и функции для управления символами Unicode.

объявленные типы mbstate_t (описаны в 7.29.1) и size_t (описанный в 7,19);

char16_t

, который является типом беззнаковых целых чисел, используемым для 16-разрядных символов, и является тем же типом как [1 112] (описанный в 7.20.1.2); и

char32_t

, который является типом беззнаковых целых чисел, используемым для 32-разрядных символов, и является тем же типом как [1 113] (также описанный в 7.20.1.2).

(Перевод перекрестных ссылок: определяет size_t, определяет mbstate_t, и определяет uint_least16_t и uint_least32_t.) заголовок также определяет минимальный набор (прерываемых) функций преобразования:

  • mbrtoc16()
  • c16rtomb()
  • mbrtoc32()
  • c32rtomb()

существуют правила, о которых символы Unicode могут использоваться в идентификаторах с помощью \unnnn или \U00nnnnnn нотации. Вам, вероятно, придется активно активировать поддержку таких символов в идентификаторах. Например, GCC требует -fextended-identifiers позволять их в идентификаторах.

Примечание, которое macOS Горная цепь (10.12.5), для именования, но одна платформа, не поддерживает .

11
задан Ether 24 August 2009 в 19:42
поделиться

4 ответа

In первое регулярное выражение . * сопоставляется два раза. В первый раз соответствует всей строке. Во второй раз он соответствует пустой строке в конце, потому что . * соответствует пустой строке, когда больше нечего сопоставить.

Этого не происходит с другим регулярным выражением, потому что . + не может соответствовать пустой строке.

Изменить: Что касается того, что и где: $ 2 будет содержать то, что было сопоставлено в последний раз . ​​* / . + применяются. $ 1 будет содержать то, что соответствует (. *) * / (. +) * , то есть всю строку.

17
ответ дан 3 December 2019 в 01:45
поделиться

Running it with "use re 'debug'" results in:

Compiling REx "((.*)*)"
Final program:
   1: OPEN1 (3)
   3:   CURLYX[0] {0,32767} (12)
   5:     OPEN2 (7)
   7:       STAR (9) # <====
   8:         REG_ANY (0)
   9:     CLOSE2 (11)
  11:   WHILEM[1/1] (0)
  12:   NOTHING (13)
  13: CLOSE1 (15)
  15: END (0)
minlen 0 

Matching REx "((.*)*)" against "This is a test string"
   0 <> <This is a >         |  1:OPEN1(3)
   0 <> <This is a >         |  3:CURLYX[0] {0,32767}(12)
   0 <> <This is a >         | 11:  WHILEM[1/1](0)
                                    whilem: matched 0 out of 0..32767
   0 <> <This is a >         |  5:    OPEN2(7)
   0 <> <This is a >         |  7:    STAR(9) # <====
                                      REG_ANY can match 21 times out of 2147483647...
  21 < test string> <>       |  9:      CLOSE2(11)
  21 < test string> <>       | 11:      WHILEM[1/1](0)
                                        whilem: matched 1 out of 0..32767
  21 < test string> <>       |  5:        OPEN2(7)
  21 < test string> <>       |  7:        STAR(9) # <====

  # This is where the outputs really start to diverge
  # --------------------------------------------------------------------------------------------
                                          REG_ANY can match 0 times out of 2147483647...
  21 < test string> <>       |  9:          CLOSE2(11) # <==== Succeeded
  21 < test string> <>       | 11:          WHILEM[1/1](0)
                                            whilem: matched 2 out of 0..32767
                                            whilem: empty match detected, trying continuation...
  # --------------------------------------------------------------------------------------------

  21 < test string> <>       | 12:            NOTHING(13)
  21 < test string> <>       | 13:            CLOSE1(15)
  21 < test string> <>       | 15:            END(0)
Match successful!

Compiling REx "((.+)*)"
Final program:
   1: OPEN1 (3)
   3:   CURLYX[0] {0,32767} (12)
   5:     OPEN2 (7)
   7:       PLUS (9) # <====
   8:         REG_ANY (0)
   9:     CLOSE2 (11)
  11:   WHILEM[1/1] (0)
  12:   NOTHING (13)
  13: CLOSE1 (15)
  15: END (0)
minlen 0 

Matching REx "((.+)*)" against "This is a test string"
   0 <> <This is a >         |  1:OPEN1(3)
   0 <> <This is a >         |  3:CURLYX[0] {0,32767}(12)
   0 <> <This is a >         | 11:  WHILEM[1/1](0)
                                    whilem: matched 0 out of 0..32767
   0 <> <This is a >         |  5:    OPEN2(7)
   0 <> <This is a >         |  7:    PLUS(9) # <====
                                      REG_ANY can match 21 times out of 2147483647...
  21 < test string> <>       |  9:      CLOSE2(11)
  21 < test string> <>       | 11:      WHILEM[1/1](0)
                                        whilem: matched 1 out of 0..32767
  21 < test string> <>       |  5:        OPEN2(7)
  21 < test string> <>       |  7:        PLUS(9) # <====

  # This is where the outputs really start to diverge
  # ------------------------------------------------------------------------------------
                                          REG_ANY can match 0 times out of 2147483647...
                                          failed... # <==== Failed
                                        whilem: failed, trying continuation...
  # ------------------------------------------------------------------------------------

  21 < test string> <>       | 12:        NOTHING(13)
  21 < test string> <>       | 13:        CLOSE1(15)
  21 < test string> <>       | 15:        END(0)
Match successful!
14
ответ дан 3 December 2019 в 01:45
поделиться

Проблема с первым регулярным выражением является комбинацией того факта, что () * сохраняет только последнее совпадение, а . * соответствует пустой строке (т.е. ничего). Таким образом, для заданного

"aaab" =~ /(.)*/;

$ 1 будет «b» . Если вы объедините это поведение с тем фактом, что . * соответствует пустой строке, вы увидите, что есть два совпадения внутреннего захвата: «Это тестовая строка» и «». Поскольку пустая строка была последней, она сохраняется в $ 2 . $ 1 - это весь захват, поэтому он эквивалентен «Это тестовая строка». "" . Второй случай работает так, как вы ожидаете, потому что . + не будет соответствовать пустой строке.

3
ответ дан 3 December 2019 в 01:45
поделиться

У меня нет ответа, но у меня есть другой способ сформулировать проблему, используя более простые и, возможно, более реалистичные регулярные выражения.

Первые два примера ведут себя именно так, как я ожидал : . * использует всю строку, а регулярное выражение возвращает список только с одним элементом. Но третье регулярное выражение возвращает список из 2 элементов.

use strict;
use warnings;
use Data::Dumper;

$_ = "foo";
print Dumper( [ /^(.*)/g ] ); # ('foo')     As expected.
print Dumper( [ /.(.*)/g ] ); # ('oo')      As expected.
print Dumper( [ /(.*)/g  ] ); # ('foo', '') Why?

Во многих ответах до сих пор подчеркивалось, что . * будет соответствовать чему угодно. Хотя это правда, этот ответ не затрагивает суть вопроса, а именно: почему обработчик регулярных выражений все еще ищет после того, как . * поглотил всю строку? В других случаях (например, в первых двух примерах) . * не добавляет лишнюю пустую строку для хорошей меры.

Обновление после полезных комментариев от Часа. Оуэнс . Первая оценка любого из трех примеров приводит к совпадению . * всей строки. Если бы мы могли вмешаться и вызвать pos () в этот момент, движок действительно был бы в конце строки (по крайней мере, так, как мы воспринимаем строку; см. Комментарии от Chas. Для более подробного понимания этого ). Однако опция / g указывает Perl снова попытаться сопоставить целое регулярное выражение. Эта вторая попытка не удастся для примеров №1 и №2, и эта неудача приведет к прекращению поиска двигателя. Однако с регулярным выражением № 3 движок получит другое совпадение: пустую строку. Затем параметр / g указывает механизму попробовать еще раз весь шаблон.

3
ответ дан 3 December 2019 в 01:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: