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