Сопоставить и разделить по регулярному выражению с начала строки

Я пытаюсь сделать терминальный парсер (для комбинатора парсеров) с нуля. Мой подход заключается в использовании regexp-match-positions* во входной строке, и если шаблон найден в первой позиции, мы выводим разделенную строку.

Это то, что у меня есть, до сих пор:

#lang racket/base

(require racket/match)

(define (make-terminal-parser pattern)
  (define (regexp-match-from-start pattern input)
    (match (regexp-match-positions* pattern input)
      [(list (cons 0 x) ...)
        (let ([index (car x)])
          (values (substring input 0 index)
                  (substring input index)))]

      [_ (error "Not found!")]))

  (lambda (input)
    (regexp-match-from-start pattern input)))

(define ALPHA (make-terminal-parser #rx"[a-zA-Z]"))

(ALPHA "hello")

Мой ALPHA, похоже, не работает, и я думаю, что это из-за того, что сопоставление с образцом ни к чему не приравнивается. В REPL (regexp-match-positions* #rx"[a-zA-Z]" "hello") выводит то, что я ожидал ('((0 . 1) (1 . 2) etc.)), поэтому я действительно не понимаю, почему это не соответствует (list (cons 0 x) ...). Если я изменю регулярное выражение на #rx"h", оно правильно разделит строку; но, очевидно, это слишком конкретно.

(В соответствующей заметке: я не понимаю, почему мне нужно (car x), чтобы получить фактическое значение индекса из совпадающих минусов.)


person Xophmeister    schedule 17.10.2017    source источник


Ответы (1)


Оказывается, проблема, с которой я столкнулся, действительно была связана с сопоставлением с образцом. Я пытался сопоставить (list (cons 0 x) ...), но документация подразумевает, что будет соответствовать только список из одного или нескольких элементов (0 . x) (где x произвольно). Это не то, чего я хочу.

Списки представляют собой серию cons, поэтому я изменил критерии соответствия на (cons (cons 0 x) _), и это дает мне то, что я хочу.

Это также объясняет, почему мне пришлось (car x) в моей предыдущей попытке. Совпадение x в (list (cons 0 x) ...) соответствовало бы каждому правому элементу каждого cons в списке, поэтому он вернул бы список. Например, '((0 . 1) (0 . 2) (0 . 3)) совпадало бы, а x равнялось бы '(1 2 3).

Итак, мой фиксированный код:

(define (make-terminal-parser pattern)
  (define (regexp-match-from-start pattern input)
    (match (regexp-match-positions pattern input)
      [(cons (cons 0 index) _)
          (values (substring input 0 index)
                  (substring input index))]

      [_ (error "Not found!")]))

  (lambda (input)
    (regexp-match-from-start pattern input)))

nb, мне также не нужно использовать помеченную звездочкой версию regexp-match-positions с сопоставлением с образцом, fwiw.

person Xophmeister    schedule 18.10.2017