【问题标题】:Map string to list racket将字符串映射到列表球拍
【发布时间】:2020-11-18 01:41:58
【问题描述】:

我想要一个函数,它接受一个字符串,由一个 python 格式的树组成,像这样

"[0, [1, 0]]"

并输出一个可用的球拍列表,像这样

'(0 (1 0))

我的第一步是将字符串转换为字符列表,用这个

(string->list treestring)

当在上面的字符串上调用时,会产生这个

'(#\[ #\0 #\, #\space #\[ #\1 #\, #\space #\0 #\] #\])

然后我打算检查我期望的各种字符并相应地解析它们,就像这样

(define (py-treestringlst-to-rkt-lst treestringlst result)
 (cond
  [(empty? treestringlst) result]
  [(char=? (car treestringlst)  #\[) (append (append result

但我在这里停了下来,因为我意识到我不知道如何在球拍中构建一个不闭合的括号。

我想更优雅的解决方案将涉及build-list;一个左括号 #\[ 将被解释为在每个后续字符上运行构建列表,直到找到一个右括号 #\]

但也许我缺少一种更简单的方法,因为(如果还不清楚的话)我是一个新手敲诈者。

编辑:

非常感谢,ex nihilo 和 Óscar López。既然我犯了下面的暴行,我相信我可以更好地欣赏您的解决方案的优雅以及它们所表现出的精通。但是,我并没有假装自己是 Racket 的狂热学生,以至于我宁愿在续集之前阅读你的书,从而避免了自己的心痛。

; On the other hand, it works — kind of. Always gives a result two layers deep, but I could fix that.... enough... to bed with me
(define (py-treestringlst-to-rkt-lst treestringlst result)
 (cond
  [(empty? treestringlst) result]
  [(char=? (car treestringlst)  #\[) (py-treestringlst-to-rkt-lst (cdr treestringlst) (append result (build-list 1 (lambda (x) '()))))]
  [(char=? (car treestringlst)  #\]) (py-treestringlst-to-rkt-lst (cdr treestringlst) (append result '(bracket)))]
  [(and (char=? (car treestringlst)  #\0) (list? (last result))) (py-treestringlst-to-rkt-lst (cdr treestringlst) (reverse (cons (reverse (cons 0 (reverse (car (reverse result))))) (cdr (reverse result)))))]
  [(and (char=? (car treestringlst)  #\1) (list? (last result))) (py-treestringlst-to-rkt-lst (cdr treestringlst) (reverse (cons (reverse (cons 1 (reverse (car (reverse result))))) (cdr (reverse result)))))]
  [(and (char=? (car treestringlst)  #\0) (not (list? (last result)))) (py-treestringlst-to-rkt-lst (cdr treestringlst) (append result '(0)))]
  [(and (char=? (car treestringlst)  #\1) (not (list? (last result)))) (py-treestringlst-to-rkt-lst (cdr treestringlst) (append result '(1)))]
  [else (py-treestringlst-to-rkt-lst (cdr treestringlst) result)]))


(define (cleanit lst)
  (filter (lambda (x) (not (equal? x '()))) (filter (lambda (x) (not (equal? x 'bracket))) lst)))

; Example call
(cleanit (py-treestringlst-to-rkt-lst '(#\[
  #\[
  #\0
  #\,
  #\space
  #\1
  #\]
  #\,
  #\space
  #\0
  #\,
  #\space
  #\1
  #\,
  #\space
  #\[
  #\0
  #\,
  #\space
  #\1
  #\]
  #\,
  #\space
  #\0
  #\,
  #\space
  #\1
  #\,
  #\space
  #\0
  #\,
  #\space
  #\[
  #\1
  #\,
  #\space
  #\0
  #\]
  #\]) '()))

编辑 2(re: ex nihilo 的编辑和 tfb 的回复和评论):

确实,从无到有,我只是想出了同样的事情,使用你原来的 brackets->parenths 函数。

说我疯了,tfb,但是这个

(define (brackets->parenths s)
  (read
   (open-input-string
    (list->string (map (lambda (x)
                         (case x
                           [(#\[) #\(]
                           [(#\]) #\)]
                           [(#\') #\"]
                           [else x]))
                       (remove* '(#\,)
                                (string->list s)))))))

(brackets->parenths "['get', ['me', 'for'], 'not']")

在我看来,实际上比这更干净

(require json)

(string->jsexpr (string-replace "['get', ['me', 'for'], 'not']" "\'" "\""))

也许是因为如果我的输入变得奇怪,似乎会更容易操作。

【问题讨论】:

标签: racket


【解决方案1】:

如果您的输入受到相当大的限制——特别是如果它是 Python 文字的子集,在语法上与您的示例中的 JSON 相同,那么您可以这样做:

(require json)
(string->jsexpr "[0, [1, 0]]")

这将导致(0 (1 0))

如果你的 Python 文字子集 not 在 JSON 中是相同的,我强烈建议使用 Python 的 JSON 支持来 write JSON,然后将 JSON 读回球拍。手动重新实现大量 JSON 并不是我想要重新发明的轮子。

【讨论】:

  • 有趣。我确实计划为相关 python 列表中包含的字符串的输入创建另一个函数(或调整上述函数之一)——因此输入可能类似于"['get', ['me', 'for], 'not']"。但是,当我尝试(string->jsexpr "['get', ['me', 'for], 'not']") 时,我从球拍博士那里得到以下错误:string::2: string->jsexpr: bad input starting #"'get', ['me', 'for'], 'not']"。感谢您的回复,我想这最终会很重要。
  • 是的,那是因为 JSON 字符串有双引号。再次重申:除非您尝试解析一些 无法 转换为 JSON 的 Python 语法,否则我建议使用 JSON。
  • 现在我的球拍功能在 dr racket IDE 中工作,我正在尝试弄清楚如何在主 python 程序和这个球拍代码之间传递列表。你知道如何做到这一点吗?我知道这对 cme​​ts 来说可能太过分了。只是想知道你是否能指出我正确的方向。 (该程序在网站后面运行。)
  • @LyovinK.:我认为有很多方法——大概是某种网络/网络的东西,但我不知道这些在 Racket 中是如何工作的。
【解决方案2】:

这是一个简单的方法,使用 Racket 中的内置程序:

(define (py-treestringlst-to-rkt-lst treestringlst)
  (call-with-input-string
   (string-replace (string-replace treestringlst "," "") "'" "\"")
   read))

在 Racket 中,[] 可以用作 () 的替代品,所以我们不必对它们做任何事情。我们只需要删除逗号,用双引号替换单引号,并使用字符串端口替换read 表达式。例如:

(py-treestringlst-to-rkt-lst "[0, [1, 0]]")
=> '(0 (1 0))

(py-treestringlst-to-rkt-lst "['get', ['me', 'for'], 'not']")
=> '("get" ("me" "for") "not")

【讨论】:

    【解决方案3】:

    一种解决方案是在输入字符串中创建一个字符列表,然后删除逗号并将方括号更改为括号,然后最终使用阅读器将字符串转换为数据。 open-input-string 可以用来创建一个字符串端口,可以给read

    (define (brackets->parenths s)
      (read
       (open-input-string
        (list->string (map (lambda (x)
                             (case x
                               [(#\[) #\(]
                               [(#\]) #\)]
                               [else x]))
                           (remove* '(#\,)
                                    (string->list s)))))))
    

    示例交互:

    scratch.rkt> (brackets->parenths "[1, [2, 3]]")
    '(1 (2 3))
    scratch.rkt> (brackets->parenths "[1, [2, [3, 4, [[5, 6]]], 7], 8, 9]")
    '(1 (2 (3 4 ((5 6))) 7) 8 9)
    scratch.rkt> (brackets->parenths "[]")
    '()
    

    OP has expressed in comments 希望将字符串文字放入 Python 列表中。 Python 允许使用单引号或双引号的字符串文字,但 vanilla Racket 不允许。 Racket 阅读器在开始解析字符串对象之前必须遇到双引号字符。通过将输入中的单引号字符转换为双引号字符,可以扩展上述代码以处理所需的输入:

    (define (brackets->parenths s)
      (read
       (open-input-string
        (list->string (map (lambda (x)
                             (case x
                               [(#\[) #\(]
                               [(#\]) #\)]
                               [(#\') #\"]
                               [else x]))
                           (remove* '(#\,)
                                    (string->list s)))))))
    

    示例交互:

    scratch.rkt> (brackets->parenths "['get', ['me', 'for'], 'not']")
    '("get" ("me" "for") "not")
    

    【讨论】:

    • @Lazerbeak12345 -- 在这种情况下,语法突出显示非常糟糕,主要是因为case 表单中的替换字符,所以我完全删除了它;这似乎比帮助更分散注意力。
    • 没问题。我实际上曾怀疑是这种情况,但我想我会尝试看看您(或社区)对此的看法。
    • brackets->parenths 太长了,所以我将函数命名为exnihilo。再次感谢。想知道您是否对我刚刚针对 tfb 的回答发表的评论有任何见解,关于如何将我的球拍文件插入到我现有的 python 项目中。
    • @LyovinK。 -- 不知道有没有简单的方法可以从Python中调用Racket代码,不过你可能对Hy感兴趣,也就是a dialect of Lisp embedded in Python.可以call Hy functions directly from Python.
    • 我从未使用过 Hy,但我听说过它的好消息。关于堆栈错误,那可能是因为 Python 不支持尾调用优化; it looks like TCO can be enabled in Hy,这应该可以让您避免使用 tail recursion 的堆栈错误。你可以在 Python 中递归,你只需要避免大递归。我认为 Hy 有效地将 Lisp 语法编译为 Python 代码。 You can read more about Hy vs other Lisps here.
    猜你喜欢
    • 1970-01-01
    • 2021-03-20
    • 2018-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-15
    • 1970-01-01
    • 2013-03-16
    相关资源
    最近更新 更多