首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >按分隔符拆分字符串并包含分隔符-通用Lisp

按分隔符拆分字符串并包含分隔符-通用Lisp
EN

Stack Overflow用户
提问于 2019-12-29 02:37:46
回答 4查看 855关注 0票数 5

如何在Common中通过分隔符拆分字符串,就像在拆分序列中那样,但也可以在字符串列表中添加分隔符?

例如,我可以写:(split-string-with-delimiter #\. "a.bc.def.com"),结果是("a" "." "bc" "." "def" "." "com")

我尝试了以下代码(make-adjustable-string生成一个可以用vector-push-extend扩展的字符串):

代码语言:javascript
复制
(defun make-adjustable-string (s)
  (make-array (length s)
    :fill-pointer (length s)
    :adjustable t
    :initial-contents s
    :element-type (array-element-type s)))

(defun split-str (string &key (delimiter #\ ) (keep-delimiters nil))
  "Splits a string into a list of strings, with the delimiter still
  in the resulting list."
  (let ((words nil)
        (current-word (make-adjustable-string "")))
    (do* ((i 0 (+ i 1))
          (x (char string i) (char string i)))
         ((= (+ i 1) (length string)) nil)
      (if (eql delimiter x)
        (unless (string= "" current-word)
          (push current-word words)
          (push (string delimiter) words)
          (setf current-word (make-adjustable-string "")))
        (vector-push-extend x current-word)))
    (nreverse words)))

但这并不能打印出最后一个子字符串/单词。我不知道怎么回事。

谢谢你提前提供帮助!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2019-12-29 07:57:02

问题是在do*循环的结束条件之后。当变量i到达字符串末尾时,do*循环将退出,但仍有一个当前单词尚未添加到单词中。当满足结束条件时,在退出循环之前,需要将x添加到当前单词,然后将当前单词添加到单词:

代码语言:javascript
复制
(defun split-string-with-delimiter (string delimiter)
  "Splits a string into a list of strings, with the delimiter still
  in the resulting list."
  (let ((words nil)
        (current-word (make-adjustable-string "")))
    (do* ((i 0 (+ i 1))
          (x (char string i) (char string i)))
         ((>= (+ i 1) (length string)) (progn (vector-push-extend x current-word) (push current-word words)))
      (if (eql delimiter x)
        (unless (string= "" current-word)
          (push current-word words)
          (push (string delimiter) words)
          (setf current-word (make-adjustable-string "")))
        (vector-push-extend x current-word)))
    (nreverse words)))

但是,请注意,这个版本仍然是错误的,如果字符串的最后一个字符是分隔符,这将包含在最后一个单词中,即(split-string-with-delimiter "a.bc.def." #\.) => ("a" "." "bc" "." "def.") --我将允许您添加这个检查。

在任何情况下,您可能希望通过向前看定界符并作为一个子字符串一次提取当前i和下一个分隔符之间的所有字符来提高效率。

票数 3
EN

Stack Overflow用户

发布于 2019-12-29 14:48:10

如果你只是在寻找一个解决方案,而不是一个练习,你可以使用cl-ppcre

代码语言:javascript
复制
CL-USER> (cl-ppcre:split "(\\.)" "a.bc.def.com" :with-registers-p t)
("a" "." "bc" "." "def" "." "com")
票数 8
EN

Stack Overflow用户

发布于 2019-12-29 10:44:02

像这样吗?

使用subseq

  • using循环
  • 复制子字符串使收集东西更容易

示例:

代码语言:javascript
复制
(defun split-string-with-delimiter (string
                                    &key (delimiter #\ )
                                         (keep-delimiters nil)
                                    &aux (l (length string)))
  (loop for start = 0 then (1+ pos)
        for pos   = (position delimiter string :start start)

        ; no more delimiter found
        when (and (null pos) (not (= start l)))
        collect (subseq string start)

        ; while delimiter found
        while pos

        ;  some content found
        when (> pos start) collect (subseq string start pos)
        ;  optionally keep delimiter
        when keep-delimiters collect (string delimiter)))

示例:

代码语言:javascript
复制
CL-USER 120 > (split-string-with-delimiter "..1.2.3.4.."
                :delimiter #\. :keep-delimiters nil)
("1" "2" "3" "4")

CL-USER 121 > (split-string-with-delimiter "..1.2.3.4.."
                :delimiter #\. :keep-delimiters t)
("." "." "1" "." "2" "." "3" "." "4" "." ".")

CL-USER 122 > (split-string-with-delimiter "1.2.3.4"
                :delimiter #\. :keep-delimiters nil)
("1" "2" "3" "4")

CL-USER 123 > (split-string-with-delimiter "1.2.3.4"
                :delimiter #\. :keep-delimiters t)
("1" "." "2" "." "3" "." "4")

或修改以处理任何序列(列表、向量、字符串、.):

代码语言:javascript
复制
(defun split-sequence-with-delimiter (sequence delimiter
                                      &key (keep-delimiters nil)
                                      &aux (end (length sequence)))
  (loop for start = 0 then (1+ pos)
        for pos   = (position delimiter sequence :start start)

        ; no more delimiter found
        when (and (null pos) (not (= start end)))
        collect (subseq sequence start)

        ; while delimiter found
        while pos

        ;  some content found
        when (> pos start) collect (subseq sequence start pos)
        ;  optionally keep delimiter
        when keep-delimiters collect (subseq sequence pos (1+ pos))))
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59516459

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档