【问题标题】:Repeatable off-by-one issue in Common Lisp's formatCommon Lisp 格式的可重复问题
【发布时间】:2016-01-18 23:31:55
【问题描述】:

我有 format 的标签 ~VT 行为不同,具体取决于换行符 ~% 是在行首还是行尾,我想知道为什么。不同之处在于,当换行符位于行尾时,制表位的仅在第一个实例中似乎有一个额外的空间。以下示例说明。示例中唯一的区别在于格式控制字符串:第一个示例中为"~%~A~VT= ~A",第二个示例中为"~A~VT= ~A~%"

示例 1:输出行开头的换行符

(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"

这里的行为符合预期。

示例 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,并没有在其他实现上尝试过。这可能是一个错误,但它的预期行为似乎更合理,但我不明白它可以完成什么,我无法在格式的文档中找到解释。

【问题讨论】:

  • 在 CCL 和 CLISP 中为我工作。 (顺便说一句,mapc 是首选的副作用。)
  • CMUCL 的相同问题 (snapshot-2016-01)。由于 SBCL 是从它派生的,因此问题可能源于该实现。
  • @danlei -- 我确认 CLISP 确实显示异常。

标签: common-lisp


【解决方案1】:

我认为这是一个错误。我也可以使用 SBCL 1.3.1 在 Linux 上重现它。

~T 在某些情况下可能需要启发式(可能会失败)来确定当前列,但我猜字符串的开头应该被视为第 0 列。

至少在我的电脑上,使用简单的with-output-to-string时似乎不会出现这种情况:

(with-output-to-string (s)
  (mapcar (lambda (line)
            (format s "~A~VT= ~A~%" line 10 42))
          '(a abcd asdf foobar g november)))

但是,当您将预制字符串提供给 with-output-to-string 时,它确实会发生:

(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))

【讨论】:

  • 请注意,文档有一些关于确定初始列的特定 cmets,lispworks.com/documentation/HyperSpec/Body/22_cfa.htm
  • "如果由于某种原因无法通过直接查询来确定当前的绝对列位置,则 format 可以通过注意某些指令(例如 ~% 或 ~&,或 ~A 参数是包含换行符的字符串)导致列位置重置为零,并计算自该点以来发出的字符数。"
  • "如果失败,format 可能会尝试在调用 format 时目标位于第 0 列的风险更高的假设上进行类似的推导。如果即使这种启发式失败或在实现上不方便,最坏的情况是 ~T操作只会输出两个空格。”
猜你喜欢
  • 2016-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-10
  • 2022-01-15
  • 1970-01-01
  • 2017-02-27
相关资源
最近更新 更多