[英]Racket pattern matching of lists
我正在嘗試與列表進行模式匹配,但是由於某些原因,當我執行以下操作時會得到意外的匹配:
> (define code '(h1 ((id an-id-here)) Some text here))
> (define code-match-expr '(pre ([class brush: python]) ...))
> (match code
[code-match-expr #t]
[_ #f])
#t
問題:為什么code
與code-match-expr
?
我在Racket REPL中進行了嘗試,因為我實際上想解決另一個實際問題:使用Pollen的pygments包裝函數突出顯示代碼,這些代碼稍后將以HTML輸出。 為此,我編寫了以下代碼,以解決問題:
(define (read-post-from-file path)
(Post-from-content (replace-code-xexprs (parse-markdown path))))
(define (replace-code-xexprs list-of-xexprs)
;; define known languages
(define KNOWN-LANGUAGE-SYMBOLS
(list 'python
'racket
'html
'css
'javascript
'erlang
'rust))
;; check if it matches for a single language's match expression
;; if it mathces any language, return that language's name as a symbol
(define (get-matching-language an-xexpr)
(define (matches-lang-match-expr? an-xexpr lang-symbol)
(display "XEXPR:") (displayln an-xexpr)
(match an-xexpr
[`(pre ([class brush: ,lang-symbol]) (code () ,more ...)) lang-symbol]
[`(pre ([class brush: ,lang-symbol]) ,more ...) lang-symbol]
[_ #f]))
(ormap (lambda (lang-symbol)
;; (display "trying to match ")
;; (display an-xexpr)
;; (display " against ")
;; (displayln lang-symbol)
(matches-lang-match-expr? an-xexpr lang-symbol))
KNOWN-LANGUAGE-SYMBOLS))
;; replace code in an xexpr with highlightable code
;; TODO: What happens if the code is in a lower level of the xexpr?
(define (replace-code-in-single-xexpr an-xexpr)
(let ([matching-language (get-matching-language an-xexpr)])
(cond [matching-language (code-highlight an-xexpr matching-language)]
[else an-xexpr])))
;; apply the check to all xexpr
(map replace-code-in-single-xexpr list-of-xexprs))
(define (code-highlight language code)
(highlight language code))
在此示例中,我將解析具有以下內容的降價文件:
# Code Demo
```python
def hello():
print("Hello World!")
```
我得到以下xexpr
:
1。
(h1 ((id code-demo)) Code Demo)
2。
(pre ((class brush: python)) (code () def hello():
print("Hello World!")))
但是,由於某種原因,這些都不匹配。
match
是語法,不評估模式。 由於code-match-expr
是一個符號,它將把整個表達式(評估code
結果)綁定到變量code-match-expr
並在模式匹配時評估其余的表達式。 結果將始終為#t
。
請注意,第二個模式符號_
是相同的模式 。 它也匹配整個表達式,但是_
的特殊之處在於它不會像code-match-expr
那樣被綁定。
重要的是,永遠不要使用您定義的變量code-match-expr
,但是由於match
綁定了一個具有相同名稱的變量,因此在進行match
原始綁定將被遮蓋。
可以正常工作的代碼如下所示:
(define (test code)
(match code
[`(pre ([class brush: python]) ,more ...) #t]
[_ #f]))
(test '(h1 ((id an-id-here)) Some text here))
; ==> #f
(test '(pre ((class brush: python))))
; ==> #t
(test '(pre ((class brush: python)) a b c))
; ==> #t
正如您所看到的,more ...
表示零個或多個,並且忽略哪種括號,因為在Racket []
中與()
和{}
。
編輯
您仍然有點落后。 在此代碼中:
(define (matches-lang-match-expr? an-xexpr lang-symbol)
(display "XEXPR:") (displayln an-xexpr)
(match an-xexpr
[`(pre ([class brush: ,lang-symbol]) (code () ,more ...)) lang-symbol]
[`(pre ([class brush: ,lang-symbol]) ,more ...) lang-symbol]
[_ #f]))
打包模式后,由於未對lang-symbol
進行引用,因此它將匹配原子的任何內容,並將其綁定為該子句中的變量。 它與具有相同名稱的綁定變量無關 ,因為match
不使用變量,而是創建變量。 您返回變量。 從而:
(matches-lang-match-expr? '(pre ([class brush: jiffy]) bla bla bla) 'ignored-argument)
; ==> jiffy
這是您想要做的事情:
(define (get-matching-language an-xexpr)
(define (get-language an-xexpr)
(match an-xexpr
[`(pre ([class brush: ,lang-symbol]) (code () ,more ...)) lang-symbol]
[`(pre ([class brush: ,lang-symbol]) ,more ...) lang-symbol]
[_ #f]))
(let* ((matched-lang-symbol (get-language an-xexpr))
(in-known-languages (memq matched-lang-symbol KNOWN-LANGUAGE-SYMBOLS)))
(and in-known-languages (car in-known-languages))))
同樣,。 match
濫用准引用與創建列表結構完全不同。 它使用它們來匹配文字並將未加引號的符號捕獲為變量。
確保您清楚匹配的內容。 在Racket x表達式中,屬性名稱是符號,但值是字符串。 因此,您要匹配的表達式將類似於(pre ([class "brush: js"])) ___)
- 不是 (pre ([class brush: js]) ___)
。
要匹配該字符串並提取"brush: "
之后的部分,可以使用pregexp
匹配模式。 這是Frog用於提取要提供給Pygments的語言的代碼段 :
(for/list ([x xs])
(match x
[(or `(pre ([class ,brush]) (code () ,(? string? texts) ...))
`(pre ([class ,brush]) ,(? string? texts) ...))
(match brush
[(pregexp "\\s*brush:\\s*(.+?)\\s*$" (list _ lang))
`(div ([class ,(str "brush: " lang)])
,@(pygmentize (apply string-append texts) lang
#:python-executable python-executable
#:line-numbers? line-numbers?
#:css-class css-class))]
[_ `(pre ,@texts)])]
[x x])))
(這里pygmentize
是其他Frog源代碼中定義的函數;它是將Pygments作為單獨的進程運行並對其之間進行管道pygmentize
的包裝器。但是您可以替代使用Pygments或任何其他語法突出顯示器的另一種方法。對於您來說,這是N / A關於match
問題。我只是提到它,以免分散注意力,成為另一個嵌入的問題。:))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.