Як імітувати зворотні спостереження, магістралі та диски ззаду в автоматах з кінцевим станом?


26

Я створив простий лексер регулярного вираження і аналізатор, щоб прийняти регулярний вираз і генерувати його дерево розбору. Створення недетермінованого автоматичного кінцевого стану з цього дерева розбору відносно просте для основних регулярних виразів. Однак я, здається, не можу обернути голову навколо того, як імітувати зворотні спостереження, головоломки та огляди.

З того, що я прочитав у книзі з фіолетовим драконом, я зрозумів, що для імітації значень коли регулярний вираз узгоджується, якщо і лише тоді, якщо за збігом йде відповідність регулярного виразу , ви створюєте недетермінований скінченний державний автомат, в якому замінюється . Чи можливо створити детермінований автомат з кінцевим станом, який робить те саме?r s / εr/сrс/ε

Що з імітацією негативних лукахедів та виглядів іззаду? Я дуже вдячний, якби ви зв’язали мене з ресурсом, який детально описує, як це зробити.



Відповіді:


21

Перш за все, зворотні посилання не можуть бути імітовані обмеженими автоматами, оскільки вони дозволяють описувати нестандартні мови. Наприклад, ([ab]^*)\1збігаються , що навіть не є контекстним.{шшш{а,б}}

Погляд вперед і огляд позаду не є нічого особливого у світі кінцевих автоматів, оскільки ми відповідаємо лише цілим ресурсам. Тому особлива семантика "просто перевірити, але не споживати" є безглуздою; ви просто з'єднаєте та / або перетинаєте перевірки та споживання виразів та використовуєте отримані автомати. Ідея полягає у тому, щоб перевірити висловлювання, спрямовані на випередження або відсталі, поки ви "споживаєте" вхід і зберігаєте результат у стані.

Реалізуючи регулярні вирази, потрібно запустити вхід через автомат і повернути індекси початку та кінця збігів. Це зовсім інше завдання, тому не існує насправді конструкції для кінцевих автоматів. Ви будуєте свій автомат так, як ніби вираз, спрямований на випередження або відставання, і змінюєте свій індекс, зберігаючи респ. відповідно до звітування.

Візьмемо, наприклад, оглядові частини. Ми можемо імітувати семантику regexp, виконуючи перевіряючий регулярний вираз одночасно з імпліцитно споживаючим "match-all". лише із станів, де автомат виразного виразу знаходиться в остаточному стані, може бути введений автомат захищеного виразу. Наприклад, регулярне вираження /(?=c)[ab]+/(припустимо, що є повним алфавітом) - зауважте, що воно перекладається на регулярний вираз { a , b , c } c { a , b } + { a , b , c }{а,б,c} - може відповідати{а,б,c}c{а,б}+{а,б,c}

введіть тут опис зображення
[ джерело ]

і вам би довелося

  • збережіть поточний індекс як коли ви вводите q 2 (спочатку або з q 2 ) іiq2q2
  • повідомляйте про (максимум) відповідність від до поточного індексу ( - 1 ) кожного разу, коли ви натискаєте (залишаєте) q 2 .i-1q2

Зверніть увагу, як ліва частина автомата є паралельною автоматією канонічних автоматів для [abc]*та c(повтореної) відповідно.

ijij

Зауважте, що недетермінізм притаманний цьому: основний та перспективний / автоматичний автомат може перекриватися, тому вам доведеться зберігати всі переходи між ними, щоб пізніше повідомити про відповідність або відступити.


11

Авторитетним посиланням на прагматичні проблеми, що стоять за реалізацією двигунів регулярних випромінювань, є серія з трьох дописів блогу від Расса Кокса . Як описано там, оскільки зворотні посилання роблять вашу мову нерегулярною, вони реалізуються за допомогою зворотного відстеження .

Шукаючі і дивлячісь, як і багато особливостей двигунів відповідності шаблонів регулярних виразів, не зовсім вписуються в парадигму вирішення питання про те, чи є рядок членом мови чи ні. Замість регексів ми зазвичай шукаємо підрядки у більшому рядку. "Збіги" - це підрядки, які є членами мови, а значення, що повертається, є початковою та кінцевою точками підрядки у більшому рядку.

Суть лукахедів та поглядів позаду - це не стільки в тому, щоб запровадити здатність відповідати нестандартним мовам, а скоріше налаштувати там, де движок повідомляє про початкову та кінцеву точки відповідних підрядків.

Я покладаюся на опис за адресою http://www.regular-expressions.info/lookaround.html . Двигуни регулярних виразів, що підтримують цю функцію (Perl, TCL, Python, Ruby, ...), схоже, базуються на зворотному відстеженні (тобто вони підтримують набагато більший набір мов, ніж просто звичайні мови). Вони, схоже, реалізують цю функцію як відносно "просте" розширення зворотного відстеження, а не намагаються побудувати справжні кінцеві автомати для виконання завдання.

Позитивний Lookahead

Синтаксис позитивного пошуку є (?=регулярним вираженням) . Так, наприклад, q(?=u)матчі, qлише якщо за ними дотримуються u, але не відповідають u. Я думаю, що вони реалізують це за допомогою варіації зворотного відстеження. Створіть FSM для виразу перед позитивним lookahead. Коли це збіг, згадайте, де він закінчився, і почніть новий FSM, який представляє вираз усередині позитивного пошуку. Якщо це збіги, то у вас є "відповідність", але матч "закінчується" безпосередньо перед позицією, де почався позитивний матч "лукахед".

Єдиною частиною цього, яка була б складною без зворотного відстеження, є те, що вам потрібно запам’ятати точку на вході, з якої починається пошук і перемістити вхідну стрічку назад у цю позицію після завершення матчу.

Негативний Lookahead

Синтаксис негативного пошуку є (?!регулярним вираженням) . Так, наприклад, q(?!u)матчі, qлише якщо за ним не дотримуються u. Це може бути або qнаступним яким-небудь іншим символом, або а qв самому кінці рядка. Я думаю, що це реалізується шляхом створення NFA для виразу lookahead, а потім успіху лише в тому випадку, якщо NFA не зможе відповідати наступній рядку.

Якщо ви хочете зробити це, не покладаючись на зворотний трекінг, ви можете заперечити NFA вираження lookahead, тоді ставитесь до нього так само, як ви ставитесь до позитивного lookahead.

Позитивний погляд

(?<=)(?=q)uuqqннн

Ви можете реалізувати це без зворотного відстеження, взявши перетин "рядка, який закінчується регулярним виразом ", з будь-якою частиною регулярного виразу, що знаходиться перед оператором "заднім поглядом". Це буде непросто , хоча, тому що з переглядом тому регулярний вираз , можливо , доведеться шукати далі , ніж поточне початок введення.

Негативний огляд

Синтаксис негативного вигляду - це (?<!регулярний вираз) . Так, наприклад, (?<!q)uсірники u, але тільки якщо це не передує q. Таким чином, це збігалося б з uin umbrellaі uin doubt, але не з uin quick. Знову ж таки, це, здається, робиться шляхом обчислення довжини регулярних виразів , резервного копіювання багатьох символів, тестування на матч з регулярними виразками , але тепер не вдалося провести весь матч, якщо вигляд буде збігатися.

Ви можете реалізувати це без зворотного відстеження, зробивши заперечення регулярного вираження, а потім зробивши те саме, що і для позитивного погляду позаду.


5

Принаймні, для зворотних посилань це неможливо. Наприклад, регулярний вираз (.*)\1представляє не регулярну мову. Це означає, що неможливо створити кінцевий автомат (детермінований чи ні), який би розпізнавав цю мову. Якщо ви хочете довести це формально, можете скористатися накачаною лемою .


4

Я сам розглядав це, і ви повинні мати можливість реалізувати пошук за допомогою змінної кінцевої автоматики . Коли ви стикаєтеся з lookahead, ви неефективно керуєте і lookahead, і рештою виразу, приймаючи лише якщо обидва контури приймають. Ви можете конвертувати AFA в NFA з розумним вибухом (і, таким чином, в DFA), хоча я не підтвердив, що очевидна конструкція чудово грає з групами захоплення.

Погляд з фіксованою шириною повинен бути абсолютно можливим без зворотних треків. Нехай n - ширина. Починаючи з пункту у вашій НФА, де починався огляд, ви розділили стани, дивлячись назад, так що кожен шлях у вигляд позаду закінчувався п ятьма знаками держав, які тільки зайшли в огляд. Потім додайте пошук до початку цих станів (і, за бажанням, негайно складіть підграф з AFA до NFA).

Як вже згадували інші, зворотні параметри не є регулярними, тому їх не можна реалізувати за допомогою кінцевого автомата. Насправді вони NP-завершені. У реалізації, над якою я працюю, швидке співпадіння так / ні є першорядним, тому я вирішив взагалі не застосовувати зворотні посилання.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.