I want a function that takes a string, consisting of a python-formatted tree, like this
"[0, [1, 0]]"
and outputs a useable racket list, like this
'(0 (1 0))
My first move was to convert the string to a list of chars, with this
(string->list treestring)
which, when called on the string above, results in this
'(#\[ #\0 #\, #\space #\[ #\1 #\, #\space #\0 #\] #\])
I was going then to check for the various chars I am expecting and to parse them accordingly, like this
(define (py-treestringlst-to-rkt-lst treestringlst result)
(cond
[(empty? treestringlst) result]
[(char=? (car treestringlst) #\[) (append (append result
But I stopped short here, because I realized I don't know how to build an unclosed parenthesis in racket.
I imagine the more elegant solution would involve build-list
; an open bracket #\[
would be interpreted as running build-list on every subsequent char, until a closing bracket #\]
be found.
But maybe there is an even simpler method that I am missing because (if it was not already clear) I am very much a novice racketeer.
Edit:
Thank you so much, ex nihilo and Óscar López. I believe I can better appreciate the elegance of your solutions, and the mastery they evince, now that I have committed the atrocity below. However, I do not pretend to being so avid a student of Racket that I would not rather have read yours before the sequel and so saved myself the heartache.
; 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
#\]
#\]) '()))
Edit 2 (re: ex nihilo's edit and tfb's response and comment):
Indeed, ex nihilo, I just came up with the same thing, using your original brackets->parenths
function.
Call me crazy, tfb, but this
(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']")
Actually seems cleaner, to me, than this
(require json)
(string->jsexpr (string-replace "['get', ['me', 'for'], 'not']" "\'" "\""))
Maybe because it seems like it would be easier to manipulate if my inputs get weird.