【问题标题】:Modular comparison of characters字符的模块化比较
【发布时间】:2012-07-08 08:14:48
【问题描述】:

这似乎是一个非常简单的问题,但在互联网上几乎没有关于它的文章,而且我很难自己正确地实现它。在 Java 中对 ASCII 字符实现模块化 comparison 函数的最佳方法是什么,以便比较“环绕”字母表的末尾?我想将它用于“介于”函数中,该函数可以在任意位置分割整个字母表,并在被问及“y”是否介于“x”和“b”之间时正确返回“true”。

我已经找到了所有关于字符模块化算术的问题和答案,所以我知道如何使用这样的代码进行模块化加法(字符移位):

char shifted = (((original - 'a') + 1) % 26) + 'a';

但是,这是基于 Java 内置的模块化算术函数,没有可比较的等效函数。即使我使用的是普通整数,我也无法询问 Java 是否 a

所以一般的问题是,在 Java 中实现模块化比较操作的最佳方式是什么?如果这个问题太难了,至少有办法让这种比较适用于 ASCII 字母表吗?

【问题讨论】:

  • 请注意,“模比较”对于二进制比较没有意义:模算术中没有“小于”顺序。不过,“介于”之间的事情仍然是可能的,因此您的问题仍然有效。

标签: java math ascii string-comparison


【解决方案1】:

根据您的喜好,您可能希望使用模数运算符而不是 if 语句。要在一行中执行比较,请执行以下操作:

public static boolean isStrictlyBetween(char a, char x, char b) {
    // assuming x, a, and b are all the same case (lower or upper).
    return ((x - a + 26) % 26) < ((b - a + 26) % 26);
}

此代码表示如果从 a 到 x 的顺时针距离小于从 a 到 b 的顺时针距离,则返回 true。 +26 确保差异表达式的结果是正的(负数的百分比在某些语言中表现得很奇怪)。 % 26 执行您想要的模数。

【讨论】:

    【解决方案2】:

    在循环队列中对A &lt; B &lt; C 进行测试时,您始终可以假设A &lt;= B 已绕行或未绕行。

    如果A &lt; B,则没有发生换行。如果是B &lt; C or C &lt; A,则B在A和C之间。

    如果A &gt; B,那么你已经包裹了。如果B &lt; C and C &lt; A,那么B在A和C之间。

    您需要自己定义如何处理 A==B、B==C 或 A==C。

    【讨论】:

    • 这非常简单。最好的部分是它不依赖于字母表的长度,所以即使我的字符串可能包含标点符号或 Unicode 字符,我也可以使用相同的函数,而无需更改幻数 26。
    • 它也适用于具有可比值但不一定从头到尾连续的字母,例如十六进制或 base64。
    【解决方案3】:

    所以你的问题是:字符 c_1 是否介于字符 c_2c_3 之间,前提是字母环绕?

    • 将每个字符转换为数字(即a = 1b = 2、...、z = 26)。在您的示例中,这将是介于 c_2 = 'x' = 24c_3 = 'b' = 2 之间的 c_1 = 'y' = 25
    • 如果c_3 &lt; c_2,将26 加到c_3。在您的示例中,情况就是这样,因为2 &lt; 24
    • 我们现在有c_1 = 25c_2 = 24c_3 = 28
    • 检查c_1 &gt;= c_2 &amp;&amp; c_1 &lt;= c_3 是否成立。如果是这样,则字符位于两个边界之间。如果不成立,则继续下一步。
    • 将 26 添加到 c_1 并检查此值是否满足上述检查。如果是这样,则该字符在包装边界内。如果没有,则停止。

    在这种方法中,您基本上是在“第二个”字母表中添加 26。所以:

    ... 23 24 25 26 1 2 3 4
    

    变成:

    ... 23 24 25 26 27 28 29 30
    

    然后你就可以像往常一样做算术了。

    编辑:根据 MvG 的评论更新算法。确实有多种情况:“24和2之间是25吗?”还有“1在24和2之间吗?”。在后一种情况下,您还需要检查 (1 + 26) 是否在 24 和 (2 + 26) 之间 - 这成立,因此字符 'a' 确实介于 'x' 和 'b' 之间。

    【讨论】:

    • 您还应该将 26 添加到 c_1 并查看是否在范围内。
    猜你喜欢
    • 2018-03-20
    • 2010-10-15
    • 1970-01-01
    • 2013-03-04
    • 1970-01-01
    • 1970-01-01
    • 2013-08-12
    • 2012-06-06
    相关资源
    最近更新 更多