Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
LISP-新列表中还包括带分隔符的拆分字符串_Lisp_Common Lisp_List Processing - Fatal编程技术网

LISP-新列表中还包括带分隔符的拆分字符串

LISP-新列表中还包括带分隔符的拆分字符串,lisp,common-lisp,list-processing,Lisp,Common Lisp,List Processing,我有以下元素的列表 ("(aviyon" "213" "flyingman" "no))") as list 我想要的是,我想使用括号作为拆分器拆分包含字符串的列表,但也希望在不破坏顺序的情况下将这些括号包含在新列表中 我所需的新列表输出或修改的相同列表 ("(" "aviyon" "213" "flyingman" "no" ")" ")") 我来自命令语言,这将是java或C++的15分钟工作。但在这里我被困在做什么。我知道我必须这么做 1-从循环中的列表中获取元素 我想这是用第n个1

我有以下元素的列表

("(aviyon" "213" "flyingman" "no))") as list
我想要的是,我想使用括号作为拆分器拆分包含字符串的列表,但也希望在不破坏顺序的情况下将这些括号包含在新列表中

我所需的新列表输出或修改的相同列表

("(" "aviyon" "213" "flyingman" "no" ")" ")") 
我来自命令语言,这将是java或C++的15分钟工作。但在这里我被困在做什么。我知道我必须这么做

1-从循环中的列表中获取元素

我想这是用第n个1'列表名完成的

2-在不删除放入新列表的分隔符的情况下进行分隔

我找到了像SPLIT-SEQUENCE这样的函数,但我不能不删除它,也不能不打破原来的顺序


任何帮助都将不胜感激。

您可以使用cl ppcre库来完成这项工作

例如:

CL-USER> (ql:quickload :cl-ppcre)

CL-USER> (cl-ppcre:split "([\\(\\)])" "(aviyon" :with-registers-p t)
("" "(" "aviyon")
CL-USER> (cl-ppcre:split "([\\(\\)])" "no))" :with-registers-p t)
("no" ")" "" ")")
CL-USER> 
但是,它在列表中生成空字符串。使用remove if函数清除它们:

CL-USER> (defun empty-string-p (s) (string= s ""))
EMPTY-STRING-P
CL-USER> (remove-if 'empty-string-p
                    (list "no" ")" "" ")"))
("no" ")" ")")
最后,您可以构造一个兼有这两种功能的函数,并在命令式循环中运行它是的,Common Lisp并不像许多人认为的那样起作用:

CL-USER> (defun remove-empty-strings (l)
           (remove-if 'empty-string-p l))
REMOVE-EMPTY-STRINGS
CL-USER> (defun split (s)
           (cl-ppcre:split "([\\(\\)])"
                           s
                           :with-registers-p t))
SPLIT
CL-USER> (defparameter *the-list* '("(aviyon" "213" "flyingman" "no))"))
*THE-LIST*
CL-USER> (loop for item in *the-list*
               for splitted = (split item)
               for cleaned = (remove-empty-strings splitted)
               append cleaned)
("(" "aviyon" "213" "flyingman" "no" ")" ")")

您可以使用cl ppcre库来完成此工作

例如:

CL-USER> (ql:quickload :cl-ppcre)

CL-USER> (cl-ppcre:split "([\\(\\)])" "(aviyon" :with-registers-p t)
("" "(" "aviyon")
CL-USER> (cl-ppcre:split "([\\(\\)])" "no))" :with-registers-p t)
("no" ")" "" ")")
CL-USER> 
但是,它在列表中生成空字符串。使用remove if函数清除它们:

CL-USER> (defun empty-string-p (s) (string= s ""))
EMPTY-STRING-P
CL-USER> (remove-if 'empty-string-p
                    (list "no" ")" "" ")"))
("no" ")" ")")
最后,您可以构造一个兼有这两种功能的函数,并在命令式循环中运行它是的,Common Lisp并不像许多人认为的那样起作用:

CL-USER> (defun remove-empty-strings (l)
           (remove-if 'empty-string-p l))
REMOVE-EMPTY-STRINGS
CL-USER> (defun split (s)
           (cl-ppcre:split "([\\(\\)])"
                           s
                           :with-registers-p t))
SPLIT
CL-USER> (defparameter *the-list* '("(aviyon" "213" "flyingman" "no))"))
*THE-LIST*
CL-USER> (loop for item in *the-list*
               for splitted = (split item)
               for cleaned = (remove-empty-strings splitted)
               append cleaned)
("(" "aviyon" "213" "flyingman" "no" ")" ")")
解决方案

因为你不理解Alexander的解决方案,因为我写了我的解决方案:

;; load two essential libraries for any common lisper
(ql:quickload :cl-ppcre)
(ql:quickload :alexandria)
;; see below to see how to install quicklisp for `ql:quickload` command
;; it is kind of pythons `import` and if not install `pip install`
;; in one command for common-lisp

(defun remove-empty-string (string-list) 
  (remove-if #'(lambda (x) (string= x "")) string-list))


(defun split-parantheses-and-preserve-them (strings-list)
  (remove-empty-string 
  (alexandria:flatten 
    (mapcar #'(lambda (el) (cl-ppcre:split "(\\(|\\))" 
                                           el 
                                           :with-registers-p t)) 
            strings-list))))

 ;; so now your example
 (defparameter *list* '("(aviyon" "213" "flyingman" "no))"))

 (split-parantheses-and-preserve-them *list*)
 ;; returns:
 ;; ("(" "aviyon" "213" "flyingman" "no" ")" ")")
这是怎么回事

cl ppcre:split\\\\\\\a-string 将字符串拆分为或。因为在正则表达式模式中,或者用于捕获匹配-就像这里一样,外部的偏执狂捕获-你必须逃离它们或\\。 因此,使用cl-ppcre:split,您可以通过正则表达式模式拆分公共lisp中的任何字符串。由Edi Weitz编写的超级酷和超级高效的软件包。他为common lisp编写了几个超级复杂的软件包,在社区中它们也被称为ediware或edicls。 顺便说一句-cl-ppcre甚至比正则表达式的黄金标准:perl正则表达式引擎更高效、更快

:with-REGISTERS-PT选项将保留匹配的分隔符-必须用括号捕获,如:在模式中

将其映射到列表上,以将其应用于字符串列表中的每个字符串元素

然而,在那之后你得到的是一个列表。 每个内部列表包含列表中每个字符串元素的拆分结果

展平列表:展平。 对于许多不符合lisp标准的函数,但您认为它们是基本的函数(如展平列表),请始终首先在alexandria中查看-大多数情况下,它有一个您想要的函数-它是一个巨大的库。这就是为什么您需要它作为一个普通的lisper

但仍然会有一些空字符串需要删除。 这就是为什么我编写了remove空字符串,它使用remove if-和remove if not是列表的标准过滤函数。 它采用了一个谓词函数——这里的lambda x string=x,如果string是空字符串,则给出T,否则给出NIL。 它将删除函数中生成的展开列表中的所有元素,这些元素都是空字符串。 在其他语言中,它将被命名为filter,但是的,有时公共lisp中的函数名选择得不是很好。有时,我认为我们应该创建别名,然后移到别名上,并保留旧名称以实现向后兼容性。Clojure有更好的函数名。。。也许cl人应该超越clojure函数名

快速口齿

@亚历山大·阿尔特门科(Alexander Artemenko)写的正是我的解决方案——他是第一个。我将补充: 如果您对CommonLisp如此陌生,可能您不知道如何使用quicklisp。 在终端linux或macos中执行以下操作:

wget https://beta.quicklisp.org/quicklisp.lisp
否则,请在windows中从该地址手动下载

我把它放在~/quicklisp文件夹中

然后在clisp或sbcl中执行以下操作:

(load "~/quicklisp/quicklisp.lisp") ;; just path to where downloaded
;; quicklisp.lisp file is!

;; then install quicklisp:
(quicklisp-quickstart:install)

;; then search for cl-ppcre
(ql:system-apropos "cl-ppcre")

;; then install cl-ppcre
(ql:quickload "cl-ppcre")

;; and to autoload everytime you start sbcl or clisp
;; in linux or mac - sorry I don't now windows that well
;; I have the opinion every programmer should us unix
;; as their OS
;; you have to let quicklisp be loaded when they start
;; by an entry into the init file
;; mostly located in ~/.sbclrc or ~/.clisprc.slip or such ...
;; respectively.
;; quicklisp does an entry automatically if you do:
(ql:add-to-init-file)

;; after installation do:
(quit)

;; If you then restart sbcl or clisp and try:
(ql:quickload :cl-ppcre)
;; it should work, - if not, you have to manually load
;; quicklisp first
(load "~/quicklisp/setup.lisp") ;; or wherever quicklisp's
;; setup.lisp file has been stored in your system!
;; and then you can do
(ql:quickload :cl-ppcre)

;; to install alexandria package then, do
(ql:quickload :alexandria) ;; or "alexandria"

;; ql:quickload installs the package from quicklisp repository,
;; if it cannot find package on your system.

;; learn more about quicklisp, since this is the package
;; manager of common lisp - like pip for python
解决方案

因为你不理解Alexander的解决方案,因为我写了我的解决方案:

;; load two essential libraries for any common lisper
(ql:quickload :cl-ppcre)
(ql:quickload :alexandria)
;; see below to see how to install quicklisp for `ql:quickload` command
;; it is kind of pythons `import` and if not install `pip install`
;; in one command for common-lisp

(defun remove-empty-string (string-list) 
  (remove-if #'(lambda (x) (string= x "")) string-list))


(defun split-parantheses-and-preserve-them (strings-list)
  (remove-empty-string 
  (alexandria:flatten 
    (mapcar #'(lambda (el) (cl-ppcre:split "(\\(|\\))" 
                                           el 
                                           :with-registers-p t)) 
            strings-list))))

 ;; so now your example
 (defparameter *list* '("(aviyon" "213" "flyingman" "no))"))

 (split-parantheses-and-preserve-them *list*)
 ;; returns:
 ;; ("(" "aviyon" "213" "flyingman" "no" ")" ")")
这是怎么回事

cl ppcre:split\\\\\\\a-string 将字符串拆分为或。因为在正则表达式模式中,或者用于捕获匹配-就像这里一样,外部的偏执狂捕获-你必须逃离它们或\\。 因此,使用cl-ppcre:split,您可以通过正则表达式模式拆分公共lisp中的任何字符串。由Edi Weitz编写的超级酷和超级高效的软件包。他为common lisp编写了几个超级复杂的软件包,在社区中它们也被称为ediware或edicls。 顺便说一句-cl-ppcre甚至比正则表达式的黄金标准:perl正则表达式引擎更高效、更快

:with-REGISTERS-PT选项将保留匹配的分隔符-必须用括号捕获,如:在模式中

将其映射到列表上,以将其应用于字符串列表中的每个字符串元素

然而,在那之后你得到的是一个列表。 每个内部列表包含每个字符串的拆分结果- 列表的元素

展平列表:展平。 对于许多不符合lisp标准的函数,但您认为它们是基本的函数(如展平列表),请始终首先在alexandria中查看-大多数情况下,它有一个您想要的函数-它是一个巨大的库。这就是为什么您需要它作为一个普通的lisper

但仍然会有一些空字符串需要删除。 这就是为什么我编写了remove空字符串,它使用remove if-和remove if not是列表的标准过滤函数。 它采用了一个谓词函数——这里的lambda x string=x,如果string是空字符串,则给出T,否则给出NIL。 它将删除函数中生成的展开列表中的所有元素,这些元素都是空字符串。 在其他语言中,它将被命名为filter,但是的,有时公共lisp中的函数名选择得不是很好。有时,我认为我们应该创建别名,然后移到别名上,并保留旧名称以实现向后兼容性。Clojure有更好的函数名。。。也许cl人应该超越clojure函数名

快速口齿

@亚历山大·阿尔特门科(Alexander Artemenko)写的正是我的解决方案——他是第一个。我将补充: 如果您对CommonLisp如此陌生,可能您不知道如何使用quicklisp。 在终端linux或macos中执行以下操作:

wget https://beta.quicklisp.org/quicklisp.lisp
否则,请在windows中从该地址手动下载

我把它放在~/quicklisp文件夹中

然后在clisp或sbcl中执行以下操作:

(load "~/quicklisp/quicklisp.lisp") ;; just path to where downloaded
;; quicklisp.lisp file is!

;; then install quicklisp:
(quicklisp-quickstart:install)

;; then search for cl-ppcre
(ql:system-apropos "cl-ppcre")

;; then install cl-ppcre
(ql:quickload "cl-ppcre")

;; and to autoload everytime you start sbcl or clisp
;; in linux or mac - sorry I don't now windows that well
;; I have the opinion every programmer should us unix
;; as their OS
;; you have to let quicklisp be loaded when they start
;; by an entry into the init file
;; mostly located in ~/.sbclrc or ~/.clisprc.slip or such ...
;; respectively.
;; quicklisp does an entry automatically if you do:
(ql:add-to-init-file)

;; after installation do:
(quit)

;; If you then restart sbcl or clisp and try:
(ql:quickload :cl-ppcre)
;; it should work, - if not, you have to manually load
;; quicklisp first
(load "~/quicklisp/setup.lisp") ;; or wherever quicklisp's
;; setup.lisp file has been stored in your system!
;; and then you can do
(ql:quickload :cl-ppcre)

;; to install alexandria package then, do
(ql:quickload :alexandria) ;; or "alexandria"

;; ql:quickload installs the package from quicklisp repository,
;; if it cannot find package on your system.

;; learn more about quicklisp, since this is the package
;; manager of common lisp - like pip for python

让我们有另一个答案,没有外部库。 就像你已经做的那样,我们可以将问题分成更小的部分:

定义一个函数,该函数从一个字符串(所有标记)构建标记列表 将此函数应用于输入列表中的所有字符串,并连接结果:

(mapcan #'all-tokens strings)
第一部分,获取一个状态并从中构建一个列表,看起来像一个展开操作变形

折叠变形,在Lisp中称为reduce,从值列表和函数以及可选的初始值构建值。 双重操作“展开”(unfold)获取一个值、一个状态、一个函数,并生成一个值列表。 在展开的情况下,step函数接受一个状态并返回新状态以及结果列表

在这里,让我们将状态定义为3个值:一个字符串、字符串中的起始位置和到目前为止解析的标记堆栈。 我们的step函数next token返回下一个状态

 ;; definition follows below
 (declare (ftype function next-token))
从字符串中获取所有标记的主函数仅计算一个固定点:

(defun all-tokens (string)
  (do (;; initial start value is 0
       (start 0)
       ;; initial token stack is nil
       (tokens))

      ;; loop until start is nil, then return the reverse of tokens
      ((not start) (nreverse tokens))

    ;; advance state
    (multiple-value-setq (string start tokens)
      (next-token string start tokens))))
我们需要一个辅助功能:

(defun parenthesisp (c)
  (find c "()"))
step函数定义如下:

(defun next-token (string start token-stack)
  (let ((search (position-if #'parenthesisp string :start start)))
    (typecase search
      (number
       ;; token from start to parenthesis
       (when (> search start)
         (push (subseq string start search) token-stack))
       ;; parenthesis
       (push (subseq string search (1+ search)) token-stack)
       ;; next state
       (values string (1+ search) token-stack))
      (null
       ;; token from start to end of string
       (when (< start (1- (length string)))
         (push (subseq string start) token-stack))
       ;; next-state
       (values string nil token-stack)))))
如果获取结果状态值并重用它们,则:

(next-token "(aviyon" 1 '("("))
"(aviyon"
NIL
("aviyon" "(")
这里,第二个返回值是NIL,它结束了生成过程。 最后,您可以执行以下操作:

(mapcan #'all-tokens '("(aviyon" "213" "flyingman" "no))"))
其中:

("(" "aviyon" "213" "flyingman" "no" ")" ")")
上面的代码并不是完全通用的,因为所有的令牌都太了解下一个令牌:您可以将其重写为任何类型的状态。 通过在状态变量中保留更多信息,还可以使用相同的机制处理字符串序列。
另外,在一个真正的lexer中,您不想反转整个令牌列表,您可以使用队列为解析器提供信息。

让我们有另一个答案,没有外部库。 就像你已经做的那样,我们可以将问题分成更小的部分:

定义一个函数,该函数从一个字符串(所有标记)构建标记列表 将此函数应用于输入列表中的所有字符串,并连接结果:

(mapcan #'all-tokens strings)
第一部分,获取一个状态并从中构建一个列表,看起来像一个展开操作变形

折叠变形,在Lisp中称为reduce,从值列表和函数以及可选的初始值构建值。 双重操作“展开”(unfold)获取一个值、一个状态、一个函数,并生成一个值列表。 在展开的情况下,step函数接受一个状态并返回新状态以及结果列表

在这里,让我们将状态定义为3个值:一个字符串、字符串中的起始位置和到目前为止解析的标记堆栈。 我们的step函数next token返回下一个状态

 ;; definition follows below
 (declare (ftype function next-token))
从字符串中获取所有标记的主函数仅计算一个固定点:

(defun all-tokens (string)
  (do (;; initial start value is 0
       (start 0)
       ;; initial token stack is nil
       (tokens))

      ;; loop until start is nil, then return the reverse of tokens
      ((not start) (nreverse tokens))

    ;; advance state
    (multiple-value-setq (string start tokens)
      (next-token string start tokens))))
我们需要一个辅助功能:

(defun parenthesisp (c)
  (find c "()"))
step函数定义如下:

(defun next-token (string start token-stack)
  (let ((search (position-if #'parenthesisp string :start start)))
    (typecase search
      (number
       ;; token from start to parenthesis
       (when (> search start)
         (push (subseq string start search) token-stack))
       ;; parenthesis
       (push (subseq string search (1+ search)) token-stack)
       ;; next state
       (values string (1+ search) token-stack))
      (null
       ;; token from start to end of string
       (when (< start (1- (length string)))
         (push (subseq string start) token-stack))
       ;; next-state
       (values string nil token-stack)))))
如果获取结果状态值并重用它们,则:

(next-token "(aviyon" 1 '("("))
"(aviyon"
NIL
("aviyon" "(")
这里,第二个返回值是NIL,它结束了生成过程。 最后,您可以执行以下操作:

(mapcan #'all-tokens '("(aviyon" "213" "flyingman" "no))"))
其中:

("(" "aviyon" "213" "flyingman" "no" ")" ")")
上面的代码并不是完全通用的,因为所有的令牌都太了解下一个令牌:您可以将其重写为任何类型的状态。 通过在状态变量中保留更多信息,还可以使用相同的机制处理字符串序列。 此外,在一个真正的lexer中,您不想反转整个标记列表,您可以使用队列为解析器提供数据。

aviyon,213,flyingman,no在Common Lisp中不是有效的列表,因为逗号作为分隔符只允许在字符串中使用。因此,有一个外部字符串未在ex中显示
足够了?你真的试过使用CommonLisp了吗?Lisp列表中没有逗号。只需启动它,您就可以交互式地找出哪些有效,哪些无效。Stackoverflow问题是最好的,当你在报告中遇到实际问题时,什么是不起作用的,如果你还没有真正学习过Lisp,那么有一些论坛可以帮助你,比如reddit.com/r/learnlisp对不起,为了更好的阅读体验,我添加了逗号。是的,在我的实际列表中,没有逗号也一样。我在原始消息中修复了这个问题。aviyon,213,flyingman,no在Common Lisp中不是有效的列表,因为逗号作为分隔符只能在字符串中使用。因此,有一个外部字符串未在示例中显示?您是否确实尝试过使用Common Lisp?Lisp列表中没有逗号。只需启动它,您就可以交互式地找出哪些有效,哪些无效。Stackoverflow问题是最好的,当你在报告中遇到实际问题时,什么是不起作用的,如果你还没有真正学习过Lisp,那么有一些论坛可以帮助你,比如reddit.com/r/learnlisp对不起,为了更好的阅读体验,我添加了逗号。是的,在我的实际列表中,没有逗号也一样。我在原始消息中修正了这一点。当然,你可以用另一种方式写这篇文章,而不用使用外部库,几乎不用考虑使用额外的内存。你能给我举个例子说明Alexeander Artemenko是如何修正的吗?因为这似乎只适用于这种情况。我的列表只能改变一件不会改变的事情我想把paranethes作为delimeter,我不想在拆分它时丢失它们。你可以通过遍历所有列表项,使用position函数在字符串中搜索,然后收集这些字符串的片段,使用sebseq函数剪切它们。当然,你可以用另一种方式写这篇文章,而不用使用外部库,几乎不用考虑——使用额外的内存。你能给我举个例子说明Alexeander Artemenko是如何写的吗?因为这似乎只适用于这种情况。我的列表只能改变一件不会改变的事情我想把paranethes作为delimeter,我不想在拆分它时丢失它们。你可以通过遍历所有列表项,使用position函数在字符串中搜索,然后收集这些字符串的片段,使用sebseq函数进行剪切。谢谢,我只得到了一个非常棒的快速提问。我看到你们两个都使用了这些库中的一个或两个函数,因此它们是开源的。我可以从cl ppcre中添加拆分函数的实现并使用它吗?如果我不使用额外的图书馆,只是想知道它会更好。当然可以。但你还是需要cl ppcre和亚历山大港。特别是cl-ppcre被hell优化。因此,建议您以任何方式使用它!因为很简单:你不能编写更好的代码,相反你会引入更多的bug,尤其是作为一个初学者。此外,这个问题不需要一个普通的分割函数,而是需要保留待分割的东西。我很可能要花15分钟才能搞定。为了匹配或在字符串中查找位置,我无论如何都会使用cl-ppcre:D。任何普通的lisper都必须学习cl ppcre和alexandria,因为它们包含了任何处理字符串和列表等的人都需要的基本函数,特别是那些想要从其他命令式函数中获得许多函数的人。它们经过了极好的测试。所以请学会使用它们!您可以使用mapcan,而不是在mapcar中使用flatten。您可以使用remove list:test'string=,而不是使用remove if进行更详细的测试。谢谢,我只需要一个简单的问题就得到了这个非常好的结果。我看到你们两个都使用了这些库中的一个或两个函数,因此它们是开源的。我可以从cl ppcre中添加拆分函数的实现并使用它吗?如果我不使用额外的图书馆,只是想知道它会更好。当然可以。但你还是需要cl ppcre和亚历山大港。特别是cl-ppcre被hell优化。因此,建议您以任何方式使用它!因为很简单:你不能编写更好的代码,相反你会引入更多的bug,尤其是作为一个初学者。此外,这个问题不需要一个普通的分割函数,而是需要保留待分割的东西。我很可能要花15分钟才能搞定。为了匹配或在字符串中查找位置,我无论如何都会使用cl-ppcre:D。任何普通的lisper都必须学习cl ppcre和alexandria,因为它们包含了任何处理字符串和列表等的人都需要的基本函数,特别是那些想要从其他命令式函数中获得许多函数的人。它们经过了极好的测试。所以请学会使用它们!您可以使用mapcan,而不是将Flatte与mapcar一起使用。您可以使用remove list:test'string=,而不是通过更详细的测试删除if。考虑到我无法破译cl pre库中调用的函数的所有连接,这非常有帮助。非常有帮助!谢谢,这是r 考虑到我无法破译cl pre库中调用的函数的所有连接,这一点非常有用。非常有帮助!