如何在Ruby中对所有可能的字符进行递增/递减操作?

11

我有一个字符串,它只有一个字符并且可以是任何可能的字符值:

irb(main):001:0> "\x0"
=> "\u0000"

我认为这可能会起作用:

irb(main):002:0> "\x0" += 1
SyntaxError: (irb):2: syntax error, unexpected tOP_ASGN, expecting $end
"\x0" += 1
        ^            from /opt/rh/ruby193/root/usr/bin/irb:12:in `<main>'

但是,正如你所看到的,它并没有这样做。我该如何增加/减少我的字符?


编辑:

Ruby似乎没有设置来做这件事。也许我走错了路。我想以8位块的形式操作原始数据。我怎样才能最好地完成这种操作?


是的,你不能对变量执行+1操作,而是要使用next、succ或!。 - Shawn Balestracci
哦,我想我不能给一个字符串字面量赋值(或者无论在 Ruby 中它们被称为什么)。 - Michael Dorst
@ShawnBalestracci,实际上那也不行。 - Michael Dorst
我认为你对对象的基本理解有所欠缺。除非对象定义了使用方法,否则您不能使用+或类似运算符。字符串支持+,但仅作为连接运算符。 - the Tin Man
4个回答

25
根据可能的值,您可以使用 String#next 方法:
"\x0".next
# => "\u0001"

或者,要更新现有的值:

c = "\x0"
c.next!

这可能并不是您想要的:

"z".next
# => "aa"

我所能想到的最简单的方法来增加一个字符的底层代码点是这样的:

c = 'z'
c = c.ord.next.chr
# => "{"

递减稍微有些复杂:

c = (c.ord - 1).chr
# => "z"

在这两种情况下,假设您不会超出0..255的范围;您可能需要添加检查以确保如此。


对于所有可能的值怎么办? 是否有一种方法总是增加字符的二进制值? 如果我从“\ x0”开始并调用足够多次的“#next”,我会得到“z”,然后我的下一个“#next”调用会给我“aa”。 我该如何避免这种情况? - Michael Dorst
另外,如何进行减法操作?作为额外的奖励,如何通过某个特定数字增加或减少值? - Michael Dorst
@anthropomorphic 我已经更新了我的答案。按一定数量增加或减少将是我演示递减的简单变体。 - Darshan Rivka Whittle

3

以下操作不可行:

"\x0" += 1

因为在 Ruby 中,这是以下简写的意思:
"\x0" = "\x0" + 1

在IT技术中,给字符串字面值赋值是一种语法错误。

但是,如果有一个整数n,可以使用pack将其转换为字符。例如:

[97].pack 'U' # => "a"

同样地,您可以使用ord将字符转换为整数。例如:
[300].pack('U').ord # => 300

使用这些方法,您可以轻松编写自己的递增函数,如下所示:
def step(c, delta=1)
  [c.ord + delta].pack 'U'
end

def increment(c)
  step c, 1
end

def decrement(c)
  step c, -1
end

如果你只想处理字节,可以使用 String#bytes,它会给你一个整数数组以供操作。您可以使用 Array#pack 将这些字节转换回字符串。(有关编码选项,请参阅文档。)


1

3
应该加入一个例子以说明为什么这是一个好的答案,而不是只给出一个单一的句子建议。 - the Tin Man
感谢您的帮助,我是个新手。我会努力改进我的回答。 - Américo Duarte

0

我认为最优雅的方法(适用于字母数字字符)是:

"a".tr('0-9a-z','1-9a-z0')

这将循环从a到z,再到数字,最后回到a。

我重新阅读了问题并发现我的答案与问题无关。我没有直接操作8位值的答案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接