创建一个包含非空白字符的字符列表。

huangapple go评论65阅读模式
英文:

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 #))

huangapple
  • 本文由 发表于 2023年5月15日 02:53:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/76249187.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定