除了使用 删除前导字符之外,是否有可能\x08
还删除尾随字符?是否有一个转义序列会删除下一个字符而不是前一个字符?
我看到 delete 显然映射到 ASCII 127,即 Hex 7F,但代码如下:
puts "a\x08b\x7fcd"
生产
b⌂cd
我预计 \x7f 会删除它后面的“c”字符,但事实并非如此。
你实际上并没有删除任何东西\x08
,你只是用“b”覆盖“a”。
想象一下您使用电传纸终端的非常古老的日子。您实际上会在纸上看到打印的“a”,电传打字机将备份一个空格,然后在其上打印“b”。所有非打印ASCII码都是为了控制电传纸终端的运动而发明的。
这正是上面的输出所做的,只有终端屏幕不会保持前一个“a”的像素点亮。
“del”字符对基本终端屏幕没有这种特殊含义。它对诸如编辑器或 shell 之类的程序可能意味着什么,但对于 STDOUT 来说,它只是另一个要打印的 ascii 字符。
“del”的原意是忽略这个字符作为输入,见:
http://en.wikipedia.org/wiki/Delete_character
我不知道您可以将 STDOUT 视为不打印下一个 CHAR 的信号的 char 之前。但是,如果您的输出是终端仿真程序(例如 xterm),您可以使用转义码做很多事情来完成您想要的。参见例如:
http://ascii-table.com/ansi-escape-sequences-vt-100.php
抽象出所有这些复杂代码的“标准”库是ncurses
,其中有几个 ruby 接口。看
退格字符(charcode ?\x08
,它的别名?\b
和它的频繁?\C-H
(Ctrl+H) 映射)与删除字符(charcode ?\x7f
,意思是 ascii 127)不同。开箱即用,两者的区别在于退格在删除之前将光标位置向左移动。
请注意,在 unix 平台上的这两种情况下,删除通常代表终止转义序列,而后者代表终止光标右侧的行(即,就像终端中的 Ctrl+K 映射)。换句话说,?\b
等价于"\e[D\e[K"
(left, kill) 和?\x7f
等价于"\e[K"
(kill)。IRB(Ruby 2.0.0,OSX)中的示例输出来说明这一点:
>> print "abc\b" # abc, backspace
ab=> nil
>> print "abc\e[D\b" # abc, left, backspace
a=> nil
>> print "abc\x7f" # abc, delete
abc=> nil
>> print "abc\e[D\x7f" # abc, left, delete
ab=> nil
>> print "abc\e[D\e[D\x7f" # abc, left, left, delete
a=> nil
>> print "abc\e[D\e[D\e[K" # abc, left, left, kill
a=> nil
上面的操作词通常是。如果您在终端中使用 getch ,其行为将与 IRB 的行为完全不同。(如果没记错的话,删除键会将角色向左移动,而不会终止该行,或者按照该顺序进行。)
澄清这一点,回到您的问题:据我所知,没有转义序列可以杀死光标位置的单个字符;仅用于终止光标左侧、右侧或两者的行的序列。如果您想深入研究,Fred 发布的参考资料非常好:
http://ascii-table.com/ansi-escape-sequences-vt-100.php
无论如何,我猜你正在玩getch
这个顺序。为了删除单个字符,您想要做的是在将字符打印到标准输出的同时保持缓冲区和光标的位置。这将允许您映射?\b
或?\x7f
按照您认为合适的方式使用以下内容:
def refresh
rest = @buffer[@position..-1]
@stdout.print "\e[K"
@stdout.print rest, "\e[#{rest.length}D" if rest && !rest.empty?
nil
end
或者,尝试通常的嫌疑人来避免头痛:readline、ncurses、highline gem 等。
这里的主要问题是:标准IO
没有短期记忆。也就是说,没有神奇的操作实体可以对即将到来的符号采取行动。以下代码片段显示“删除”,即使以现代方式提供,也不知道未来的符号:
> puts "a#{`tput dch1`}b"
# ⇒ ab
无论您是否真的需要“删除预期符号”,我都建议您为此使用普通的 ruby monkeypatch:
class String
DEL = '␡'
def postprocess
self.gsub /#{DEL}./, ''
end
end
puts "a␡bc".postprocess
# ⇒ ac
实际上,这不是直接回答您的问题,但可能会给出建议。
这是删除下一个字符的另一种方法:
class String
alias_method :default_initialize, :initialize
alias_method :default_plus, :+
attr_accessor :delnext
def initialize
default_initialize
@delnext = false
end
def +(x)
str = String(x)
str[0] = '' if @delnext
@delnext = false
default_plus str
end
end
现在,您可以执行以下操作:
s = 'test string'
s.delnext = true
s += 'test again'
s # => 'test stringest again'
同样,您可以轻松实现delprev
:
class String
def delprev
self[self.length - 1] = ''
# self # uncomment if you want delprev to return the new string
end
end
s = 'test string'
s.delprev
s # => 'test strin'