Common lisp 可在公共Lisp'中通过一个问题重复关闭;s格式

Common lisp 可在公共Lisp'中通过一个问题重复关闭;s格式,common-lisp,Common Lisp,我有format的选项卡~VT根据换行符~%是在行首还是行尾,它们的行为会有所不同,我想知道原因。不同之处在于,当换行符位于行的末尾时,似乎只有制表位的第一个实例中有额外的空间。下面的例子说明了这一点。示例中唯一的区别在于格式控制字符串:第一个示例中是“~%~A~VT=~A”,第二个示例中是“~A~VT=~A~%” 示例1:输出行开头的换行符 这里的行为与预期一样 示例2:输出行末尾的换行符 在这个例子中需要注意的是第一行 A = 42 比示例1中的对应行多出一个空间: A

我有
format
的选项卡
~VT
根据换行符
~%
是在行首还是行尾,它们的行为会有所不同,我想知道原因。不同之处在于,当换行符位于行的末尾时,似乎只有制表位的第一个实例中有额外的空间。下面的例子说明了这一点。示例中唯一的区别在于格式控制字符串:第一个示例中是
“~%~A~VT=~A”
,第二个示例中是
“~A~VT=~A~%”

示例1:输出行开头的换行符 这里的行为与预期一样

示例2:输出行末尾的换行符 在这个例子中需要注意的是第一行

A         = 42
比示例1中的对应行多出一个空间:

A        = 42
这有点难看,因为前面的双引号,这就是为什么我剪掉这个:帮助你更好地看到他们。 这可以在更大的示例上重复,并且是从更大的程序中剥离出来的MVE

(let ((sb (make-array 0
                :element-type 'character
                :adjustable t
                :fill-pointer 0)))
           (mapcar (lambda (line)
                     (format sb "~A~VT= ~A~%" line 10 42))
                   '(a abcd asdf foobar g november))
           sb)
"A         = 42
ABCD     = 42
ASDF     = 42
FOOBAR   = 42
G        = 42
NOVEMBER = 42
"

重要的问题是“为什么?”我在Mac上使用SBCL 1.3.1,还没有在其他实现上尝试过。这可能是一个bug,但它的预期行为似乎更合理,但我不明白它的预期目的是什么,我也无法在format的文档中找到解释

我认为这是一个bug。我还可以用SBCL 1.3.1在Linux上复制它

~T
在某些情况下可能需要试探法(可能会失败)来确定当前列,但我想字符串的开头应该被视为列0

至少在我的计算机上,当使用输出为字符串的简单
时,似乎不会发生这种情况:

(with-output-to-string (s)
  (mapcar (lambda (line)
            (format s "~A~VT= ~A~%" line 10 42))
          '(a abcd asdf foobar g november)))
但是,当您将预先制作的字符串赋予
,并将输出赋予字符串时,确实会发生这种情况:

(let ((sb (make-array 0
                      :element-type 'character
                      :adjustable t
                      :fill-pointer 0)))
  (with-output-to-string (s sb)
    (mapcar (lambda (line)
              (format s "~A~VT= ~A~%" line 10 42))
            '(a abcd asdf foobar g november))
    sb))

在CCL和CLISP为我工作。(顺便说一句,
mapc
对于副作用是首选。)CMUCL的问题相同(snapshot-2016-01)。由于SBCL是从它派生出来的,可能问题源于该实现。@danlei--我验证了CLISP没有显示异常。请注意,文档中有一些关于确定初始列的特定注释。“如果由于某种原因,无法通过直接查询确定当前绝对列位置,format可以通过注意某些指令(例如~%,或~&,或~A,参数为包含换行符的字符串)导致列位置重置为零来推断当前列位置,“如果失败,format可能会尝试进行类似的推断,其风险更大的假设是调用format时目标位于第0列。即使这种启发式方法失败或在实现上不方便,最坏情况下,~T操作也只会输出两个空格。”
(let ((sb (make-array 0
                      :element-type 'character
                      :adjustable t
                      :fill-pointer 0)))
  (with-output-to-string (s sb)
    (mapcar (lambda (line)
              (format s "~A~VT= ~A~%" line 10 42))
            '(a abcd asdf foobar g november))
    sb))