如何将GUI文本框中的字符串表达式转换为Scheme列表?
Scheme表达式字符串转列表的修复方案
问题现状
开发了仅支持加法和乘法的Scheme算术表达式化简程序,GUI模块中需要将用户输入的表达式字符串(如(a + (b * 1)))转换为程序可处理的Scheme列表形式,但当前convert函数的转换结果不符合预期:
> (convert "(a + b)") '(|(a| + |b)|)
问题根源
原convert函数仅通过空格分割字符串,导致括号与标识符粘在一起被识别为单个符号(如(a、b)),无法正确解析Scheme列表的结构边界。
改进方案
需要先将字符串拆分为独立的语法单元(token):把括号()、运算符+*、标识符(如a、2)分别拆成单独元素,再利用Scheme的read函数直接解析为列表。
实现代码
1. 新增tokenize辅助函数
该函数遍历字符串,将不同语法单元拆分:
(define (tokenize str) (let loop ([chars (string->list str)] [current '()] [tokens '()]) (cond [(null? chars) ;; 处理最后一个未完成的标识符 (reverse (if (null? current) tokens (cons (list->string (reverse current)) tokens)))] [(member (car chars) '(#\( #\) #\+ #\*)) ;; 遇到括号或运算符,先保存当前标识符,再添加符号 (loop (cdr chars) '() (cons (string (car chars)) (if (null? current) tokens (cons (list->string (reverse current)) tokens))))] [(char-whitespace? (car chars)) ;; 遇到空格,保存当前标识符,重置当前缓冲区 (loop (cdr chars) '() (if (null? current) tokens (cons (list->string (reverse current)) tokens)))] [else ;; 收集标识符字符(字母/数字) (loop (cdr chars) (cons (car chars) current) tokens)])))
2. 重写convert函数
利用tokenize拆分后的单元,拼接成Scheme可解析的字符串,再用read生成列表:
(define (convert str) (read (open-input-string (string-join (tokenize str) " "))))
3. 完整GUI代码
替换原convert函数后的完整代码:
(define (tokenize str) (let loop ([chars (string->list str)] [current '()] [tokens '()]) (cond [(null? chars) (reverse (if (null? current) tokens (cons (list->string (reverse current)) tokens)))] [(member (car chars) '(#\( #\) #\+ #\*)) (loop (cdr chars) '() (cons (string (car chars)) (if (null? current) tokens (cons (list->string (reverse current)) tokens))))] [(char-whitespace? (car chars)) (loop (cdr chars) '() (if (null? current) tokens (cons (list->string (reverse current)) tokens)))] [else (loop (cdr chars) (cons (car chars) current) tokens)]))) (define (convert str) (read (open-input-string (string-join (tokenize str) " ")))) ; Crée une fenêtre "Simplifier" (define frame (new frame% [label "Simplifier"])) ; Crée un conteneur "panel" (define panel (new vertical-panel% [parent frame])) ; Crée un message dans le conteneur "panel" (define msg (new message% [parent panel] [label "Donnez une expression à simplifier. N'oubliez pas les parenthèses!"])) ; Crée un champ de texte (define text-field (new text-field% (label "Expression : ") (parent panel))) ; Crée un message qui affichera le résultat (define message (new message% (parent panel) (auto-resize #t) (label " "))) ; Faire le bouton "Validez" (new button% [parent panel] [label "Validez"] ; Procédure Callback pour un clique sur le bouton "Validez": [callback (lambda (button event) (define text (simplifier (convert (send text-field get-value)))) (send message set-label (slist->string text)))]) ; Affiche la fenêtre (send frame show #t)
测试验证
> (convert "(a + b)") '(a + b) > (convert "((a + 2) * b)") '((a + 2) * b) > (convert "(a + (b * 1))") '(a + (b * 1))
内容的提问来源于stack exchange,提问作者louberlu
相关产品推荐
相关产品推荐

