英文:
How do I create a list of characters, with the non-whitespace chars nested in the list?
问题
I am trying to get a list of characters to be stored in their own list, nested in another list, that is delimited by Space chars.
我试图获取一个字符列表,将它们存储在自己的列表中,嵌套在另一个由空格字符分隔的列表中。
The expected output would be as follows: ((\#w \#o \#r \#d) \#Space (\#w \#o \#r \#d)
预期输出如下:((\#w \#o \#r \#d) \#Space (\#w \#o \#r \#d)
Here is the function that I wrote for it:
这是我为此编写的函数:
(defun string->list (str)
"Take a string, split it into chars and add it into a list."
(let ((list-string '()))
(loop for x from 0 to (- (length str) 1)
do (push (char str x) list-string))
(nreverse list-string)))
Which outputs (\#w \#o \#r \#d \#Space \#w \#o \#r \#d)
它的输出是 (\#w \#o \#r \#d \#Space \#w \#o \#r \#d)
I tried to use loops to try and get the nesting to happen, but the output ultimately was the same. I tried looking elsewhere, but couldn't find a satisfactory answer.
我尝试使用循环来尝试嵌套,但最终输出仍然相同。我也尝试寻找其他方法,但未找到满意的答案。
Here is the revised function for reference:
以下是参考的修订函数:
(defun string->list (str)
(let ((list-string '()))
(loop for letter from 0 to (- (length str) 1)
if (equal (char str letter) #\Space)
do (push (char str letter) list-string)
else
do (push (char str letter) list-string))
(nreverse list-string)))
I would appreciate some pointers of how to approach this problem. Thanks!
我希望能得到一些处理这个问题的指导。谢谢!
英文:
I am trying to get a list of characters to be stored in their own list, nested in another list, that is delimited by Space chars.
The expected output would be as follows: ((\#w \#o \#r \#d) \#Space (\#w \#o \#r \#d))
Here is the function that I wrote for it:
(defun string->list (str)
"Take a string, split it into chars and add it into a list."
(let ((list-string '()))
(loop for x from 0 to (- (length str) 1)
do (push (char str x) list-string))
(nreverse list-string)))
Which outputs (\#w \#o \#r \#d \#Space \#w \#o \#r \#d)
I tried to use loops to try and get the nesting to happen, but the output ultimately was the same. I tried looking elsewhere, but couldn't find a satisfactory answer.
Here is the revised function for reference:
(defun string->list (str)
(let ((list-string '()))
(loop for letter from 0 to (- (length str) 1)
if (equal (char str letter) #\Space)
do (push (char str letter) list-string)
else
do (push (char str letter) list-string))
(nreverse list-string)))
I would appreciate some pointers of how to approach this problem. Thanks!
答案1
得分: 1
I would use the split
function from CL-PPCRE but you can easily reimplement a similar split function (without regexes) yourself.
(rest
(mapcan (lambda (w) (list #\space (coerce w 'list)))
(ppcre:split #\space "word word")))
The call to ppcre:split
transforms:
"word word"
into
("word" "word")
Then, for each string W in the list, the lambda computes the following list, where L is a list of characters:
(#\space L)
For example:
> ((lambda (w) (list #\space (coerce w 'list))) "example")
(#\ (#\e #\x #\a #\m #\p #\l #\e))
By the way, the #\space
character is outputted as #\
in the output.
This anonymous function is called for every word resulting from the split. With the given input example, that would be twice the same list:
((#\ (#\w #\o #\r #\d))
((#\ (#\w #\o #\r #\d))
Additionally, mapcan
takes all these intermediary lists and chain them together to form a single list:
(#\ (#\w #\o #\r #\d) #\ (#\w #\o #\r #\d))
If there is at least one element, there is necessarily a superfluous #\space
in front of the list, so it discards it with rest
(which behaves appropriately too if the list is empty). Finally, the result is:
((#\w #\o #\r #\d) #\ (#\w #\o #\r #\d))
Note that if you have multiple spaces, the output is:
((#\w #\o #\r #\d) #\ NIL #\ NIL #\ NIL #\ NIL #\ (#\w #\o #\r #\d))
To me it satisfies your specification but in case you intended to split over continuous sequences of whitespaces you would need to change the regular expression that performs the split, for example:
(ppcre:split "\\s+" ...)
英文:
I would use the split
function from CL-PPCRE but you can easily reimplement a similar split function (without regexes) yourself.
(rest
(mapcan (lambda (w) (list #\space (coerce w 'list)))
(ppcre:split #\space "word word")))
The call to ppcre:split
transforms:
"word word"
into
("word" "word")
Then, for each string W in the list, the lambda computes the following list, where L is a list of characters:
(#\space L)
For example:
> ((lambda (w) (list #\space (coerce w 'list))) "example")
(#\ (#\e #\x #\a #\m #\p #\l #\e))
By the way, the #\space
character is outputted as #\
in the output.
This anonymous function is called for every word resulting from the split. With the given input example, that would be twice the same list:
((#\ (#\w #\o #\r #\d))
((#\ (#\w #\o #\r #\d))
Additionally, mapcan
takes all these intermediary lists and chain them together to form a single list:
(#\ (#\w #\o #\r #\d) #\ (#\w #\o #\r #\d))
If there is at least one element, there is necessarily a superfluous #\space
in front of the list, so it discards it with rest
(which behaves appropriately too if the list is empty). Finally, the result is:
((#\w #\o #\r #\d) #\ (#\w #\o #\r #\d))
Note that if you have multiple spaces, the output is:
((#\w #\o #\r #\d) #\ NIL #\ NIL #\ NIL #\ NIL #\ (#\w #\o #\r #\d))
To me it satisfies your specification but in case you intended to split over continuous sequences of whitespaces you would need to change the regular expression that performs the split, for example:
(ppcre:split "\\s+" ...)
答案2
得分: 1
以下是递归方法:
(defun constituent (c)
"predicate that returns T for all graphics characters except the
whitespace."
(and (graphic-char-p c)
(char/= c #\ )))
(defun string->list (str &optional (pred #'constituent) (start 0))
"Take a string, split it into chars and add it into a list."
(let ((pos-start (position-if pred str :start start)))
(when pos-start
(let ((pos-end (position-if-not pred str :start pos-start)))
(if pos-end
(cons (coerce (subseq str pos-start pos-end) 'list)
(cons #\Space (string->list str pred pos-end)))
(list (coerce (subseq str pos-start) 'list)))))))
我不知道为什么你想在两个列表之间保留一个 #\Space 字符...
英文:
Here is a recursive approach :
(defun constituent (c)
"predicate that returns T for all graphics characters except the
whitespace."
(and (graphic-char-p c)
(char/= c #\ )))
(defun string->list (str &optional (pred #'constituent) (start 0))
"Take a string, split it into chars and add it into a list."
(let ((pos-start (position-if pred str :start start)))
(when pos-start
(let ((pos-end (position-if-not pred str :start pos-start)))
(if pos-end
(cons (coerce (subseq str pos-start pos-end) 'list)
(cons #\Space (string->list str pred pos-end)))
(list (coerce (subseq str pos-start) 'list)))))))
CL-USER> (string->list "word word")
((#\w #\o #\r #\d) #\ (#\w #\o #\r #\d))
I don't know why you'd want to keep a #\Space character between the two lists...
答案3
得分: 0
我会使用额外的列表来存储当前单词,在达到单词分隔符时将其添加到列表字符串中:
(defun string->list (str)
(let (list-string word-string)
(loop for letter across str
if (equal letter #\Space)
do (progn (push (nreverse word-string) list-string)
(setq word-string nil)
(push letter list-string))
else
do (push letter word-string))
(push (nreverse word-string) list-string)
(nreverse list-string)))
英文:
I would use an extra list for the current word which gets dumped on list-string when the word delimiter is reached:
(defun string->list (str)
(let (list-string word-string)
(loop for letter across str
if (equal letter #\Space)
do (progn (push (nreverse word-string) list-string)
(setq word-string nil)
(push letter list-string) )
else
do (push letter word-string))
(push (nreverse word-string) list-string)
(nreverse list-string)))
(string->list "word1 word2")
((#\w #\o #\r #\d #) #\Space (#\w #\o #\r #\d #))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论