【问题标题】:Decrement only letters仅减少字母
【发布时间】:2016-04-03 00:25:35
【问题描述】:

我要处理一些字符串,我应该把它们放在左边N个位置来组织字符串。

这是我的代码:

private String toLeft() {
    String word = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // Example
    byte lpad = 2; // Example
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < word.length(); i++) {
        sb.append((char) (word.charAt(i) - lpad));
    }
    return sb.toString();
}

它适用于不必多次移动的输入...

所以,问题是当要移动的位置数 N 有点大(如 10)时,它返回非字母,如下例所示,我该怎么做才能防止它?

例如:ABCDEFGHIJKLMNOPQRSTUVWXYZ 如果我将每个字符向左移动 10 个位置,则返回 789:;&lt;=&gt;?@ABCDEFGHIJKLMNOP,而它必须返回 QRSTUVWXYZABCDEFGHIJKLMNOP

一些输入及其预期输出:

  • VQREQFGT // 2 positions to left == TOPCODER
  • ABCDEFGHIJKLMNOPQRSTUVWXYZ // 10 positions to left == QRSTUVWXYZABCDEFGHIJKLMNOP
  • LIPPSASVPH // 4 positions to left == HELLOWORLD

【问题讨论】:

  • 你得到的是 Z 之后的字符。你需要做一些加/减/模运算来得到正确的数字。见here

标签: java char ascii


【解决方案1】:

我认为您误解了您的(家庭作业?)要求要求您做什么。让我们看看你的例子:

VQREQFGT // 向左 2 个位置 == TOPCODER

有道理。输出中的每个字符在相应输入之前的两个字符。但是请继续阅读...

ABCDEFGHIJKLMNOPQRSTUVWXYZ // 向左 10 个位置 == QRSTUVWXYZABCDEFGHIJKLMNOP

毫无意义(字面意思)。字母 Q 不是字母表中 A 之前的 10 个字符。字母表中没有字母在A 之前。

好的,那么你如何在 10 个步骤内从 AQ

回答……你绕!

AZYXWVUTTS、@987654335...@、@987654335步骤:数一数。

所以实际要求的是左边的 N 个字符带有环绕。即使他们没有明确说明这一点,这也是示例“起作用”的唯一方式。

但是你只是在左边实现了 N 个字符没有环绕。您需要实现环绕。 (我不会告诉你怎么做,但是有很多方法可以做到。)


还有一件事。问题的标题是“仅减少字母”......这对我来说意味着您的要求是说不应该减少不是字母的字符。但是,在您的代码中,您将减少输入中的 每个 字符,无论它是否是字母。 (修复很简单……你应该自己解决。)

【讨论】:

    【解决方案2】:

    我能做些什么来预防它?

    你让它环绕。
    如果您希望一个值从 10 变为 19,然后再次从 10 开始,则在每次迭代中,您减去 10,增加 1,取除以 20 的余数,然后再次添加 10。

    只有这里,10 是'A',19 是Z,我们不是加一,而是加或减n。

    private String toLeft() {
        String word = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // Example
        byte lpad = 10; // Example
        StringBuilder sb = new StringBuilder();
        int n = -lpad;                  // I'm using n here to I can use '+ n' below
        for (int i = 0; i < word.length(); i++) {
            int shifted = word.charAt(i) - 'A' + n;
            shifted %= ('Z' - 'A' + 1); // This is for positive n
            while(shifted < 0)          // And this for negative ones
            {
                shifted += ('Z' - 'A' + 1);
            }
            sb.append((char)(shifted + 'A'));
        }
        return sb.toString();
    }
    

    【讨论】:

      【解决方案3】:

      请阅读@StephenC's excellent answer 关于环绕。简而言之,您不会向左移动,而是向左旋转,这样BAZY。当你旋转时,你会绕到另一端。

      因此,对于您希望 A-Z 旋转的字母。最简单的旋转方法是使用模数 (%)。

      你的逻辑如下:

      1. 将字母A-Z转换成数字0-25:n = ch - 'A'
      2. 应用移位和环绕。由于您要向左移动,因此要从数字中减去,因此为了防止出现负数,您首先要移动向右移动一个完整的周期:n = (n + 26 - shift) % 26
      3. 将数字转换回字母:ch = (char)(n + 'A')

      代码如下:

      private static String rotateLeft(String text, int count) {
          char[] buf = text.toCharArray();
          for (int i = 0; i < buf.length; i++)
              buf[i] = (char)((buf[i] - 'A' + 26 - count) % 26 + 'A');
          return new String(buf);
      }
      

      当然,您应该验证输入并测试您的代码:

      private static String rotateLeft(String text, int count) {
          char[] buf = text.toCharArray();
          if (count <= 0 || count >= 26)
              throw new IllegalArgumentException("Invalid count: " + count);
          for (char ch : buf)
              if (ch < 'A' || ch > 'Z')
                  throw new IllegalArgumentException("Invalid character: " + ch);
          for (int i = 0; i < buf.length; i++)
              buf[i] = (char)((buf[i] - 'A' + 26 - count) % 26 + 'A');
          return new String(buf);
      }
      
      public static void main(String[] args) {
          System.out.println(rotateLeft("VQREQFGT", 2));
          System.out.println(rotateLeft("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 10));
          System.out.println(rotateLeft("LIPPSASVPH", 4));
      }
      

      输出

      TOPCODER
      QRSTUVWXYZABCDEFGHIJKLMNOP
      HELLOWORLD
      

      【讨论】:

      • 谢谢,我没见过这种轮换方法。
      猜你喜欢
      • 2017-04-10
      • 1970-01-01
      • 2022-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多