是否有Common Lisp的格式反转?

时间:2014-05-06 08:40:34

标签: string lisp common-lisp string-parsing

我有一个困扰我一段时间的问题。 Common Lisp format函数是否可逆(至少在某种程度上),因为格式字符串可用于从format的输出中检索原始参数?我知道映射不是一对一的(一个例子是~@:(~a~),它将输入转换为大写并且不可逆),因此必然会丢失一些信息。我想到的确切地说是字符串解析的正则表达式的替代方法。例如,我希望能够写下:

(destructure-format t "[~{~a~^, ~}]" "[0, 1, 2]")

并得到回复:

=> (0 1 2)

您是否知道有任何此类尝试或论文讨论类似方法?

2 个答案:

答案 0 :(得分:4)

标准中没有任何内容

标准中没有这样的东西。 Format表达式没有足够的信息使其在任何真正意义上都有用。对于几乎没有绑定*print-readably*的所有内容,有些方法难以回读输出。在您使用列表格式提供的情况下,

(destructure-format t "[~{~a~^, ~}]" "[0, 1, 2]")

任何解决方案都必须检查format指令。什么可以毫不含糊地观察到?字符串中的第一个字符必须是#\[,最后一个字符必须是#\],而字符串中的某些出现的", "分隔输出由~a。那会有什么含糊之处呢?任何会导致", "写入输出的内容。例如,

CL-USER> (format t "[~{~a~^, ~}]" '(|, | 2 3))
[, , 2, 3]
NIL
CL-USER> (format t "[~{~a~^, ~}]" '(|, | | ,|))
[, ,  ,]
NIL
CL-USER> (format t "[~{~a~^, ~}]" '(|, | | ,| |,|))
[, ,  ,, ,]
NIL
CL-USER> (format t "[~{~a~^, ~}]" '(|, | | ,| #\,))
[, ,  ,, ,]
NIL

第三方图书馆

尽管库建议在Stack Overflow上是偏离主题的,但这个问题并没有从一个问题开始,但在看到Rörd's answer建议使用外部函数调用C scanf之后,我很快就搜索了在CLiki上扫描并找到format-setf(并重新阅读评论,我看到Xach found it first),其描述如下:

  

Common Lisp等效于scanf()。

     

关于comp.lang.lisp的(相对)常见问题是“什么是   相当于scanf()?“。通常的答案是”没有一个,   因为要弄清楚应该发生什么事情太难了。这是公平的   够了。

     

然而,一年Christophe在考试期间感到无聊,所以他写道   format-setf.lisp,可以做你想做的事。

     

应该指出目前这个程序的行为   没有具体说明,在更多的意义上,而不仅仅是对符号的破坏   “CL”包。什么是好的将是看到规范   因为它的行为而出现,所以当人们没有借口时   说这是马车。

其他替代方案

由于你真的最终会问“这可能匹配的可能的方式是什么,你基本上要求一个正则表达式以及那些格式化的额外东西。” p>

  

我想到的只是常规的替代品   字符串解析的表达式。

如果您正在寻找正则表达式,那么正则表达式非常合适。如果你正在寻找那些不是正则表达式的解析,那么你可能想要编写一个真正的解析器。它可能是第一次令人生畏,但在那之后,它变得更容易,而Common Lisp使它相对无痛。甚至还有解析器生成库。另一方面,如果您正在寻找序列化和反序列化,那么Common Lisp读取器和编写器使s表达式成为一个不错的选择。

答案 1 :(得分:1)

如果您想要基于格式字符串的解析,但不需要format的高级功能,则可以通过FFI使用C&#39 {s} scanf功能。以下是使用CFFI执行此操作的示例:

(with-foreign-strings ((input "[0, 1, 2]") (format "[%d, %d, %d]"))
  (with-foreign-objects ((a :int) (b :int) (c :int))
    (foreign-funcall "sscanf" :pointer input :pointer format
                     :pointer a :pointer b :pointer c)
    (loop for x in (list a b c) collect (mem-ref x :int))))