【问题标题】:How to shift each letter of the string by a given number of letters?如何将字符串的每个字母移动给定数量的字母?
【发布时间】:2011-09-20 10:33:54
【问题描述】:

如何在不使用硬编码字典的情况下,在 bash 中将字符串的每个字母向下或向上移动给定数量的字母?

【问题讨论】:

    标签: bash string


    【解决方案1】:
    $ alpha=abcdefghijklmnopqrstuvwxyz
    $ rot=3
    $ sed "y/${alpha}/${alpha:$rot}${alpha::$rot}/" <<< 'foobar'
    irredu
    

    【讨论】:

    • 这看起来更加灵活。它适用于 rot=3 的 xyz 吗?是的,它确实。来自我的 +1
    • 这似乎不适用于大写字母
    【解决方案2】:

    你的意思是像ROT13这样的吗:

    pax$ echo 'hello there' | tr '[a-z]' '[n-za-m]'
    uryyb gurer
    
    pax$ echo 'hello there' | tr '[a-z]' '[n-za-m]' | tr '[a-z]' '[n-za-m]'
    hello there
    

    对于想要提供任意旋转(0 到 26)的更通用的解决方案,您可以使用:

    #!/usr/bin/bash
    
    dual=abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
    phrase='hello there'
    rotat=13
    newphrase=$(echo $phrase | tr "${dual:0:26}" "${dual:${rotat}:26}")
    echo ${newphrase}
    

    【讨论】:

    • 检查您的发行版,/usr/bin/usr/games 中可能有一个 rot13 工具,这将是另一种方法。
    • 包含任何可见字符的移位怎么样? (大写、数字、!@#$%^&*()_+ 等)
    【解决方案3】:

    如果你也想旋转大写字母,你可以使用这样的东西:

    cat data.txt | tr '[a-z]' '[n-za-m]' | tr '[A-Z]' '[N-ZA-M]'
    

    data.txt 包含您想要旋转的任何内容。

    【讨论】:

      【解决方案4】:

      或者

      cat data.txt | tr 'a-zA-Z' 'n-za-mN-ZA-M' 
      

      它也可以工作

      【讨论】:

        【解决方案5】:
        Shift by 12 characters(A becomes M, and vice versa)
        
        Encryption
        ----------
        $> echo ABCDE | tr '[A-Z]' '[M-ZA-L]' // prints MNOPQ
        
        Decryption
        ----------
        $> echo MNOPQ | tr '[M-ZA-L]' '[A-Z]' // prints ABCDE
        

        在加密示例中,我们将 ABCDE 传递给命令tr,该命令有两个参数。第一个是匹配的字符串。它将匹配您输入中的某些字符串(在我们的例子中为 ABCDE)。第二个参数作用于第一个参数的结果并相应地修改它。因此,我们基本上匹配输入 ABCDE 中存在的任何大写字母并将其传递给第二个参数。第二个参数将字符替换为下一个对应的第 12 个字符。现在,这部分理解起来很重要,可能会让一些人感到困惑,我们基本上是从第二个参数中的[M-L] 开始的。由于tr 命令不直接接受这个,我们将它分成两个单独的块。第一个块是[M-Z],第二个块是[A-L]。它基本上就像一个搜索和替换机制。你用第一个参数搜索,用第二个参数修改,就这么简单。

        对于第二个示例,我刚刚在tr 命令中将第一个参数与第二个参数进行了交换。它完美地充当解密器。你可以像第一个例子一样写它,但是我发现当我有加密算法时它更省时,我也可以交换参数来有一个解密算法。

        【讨论】:

        • 虽然这段代码可以为这个问题提供一个解决方案,但最好添加上下文来说明它为什么/如何工作。这可以帮助未来的用户学习并最终将这些知识应用到他们自己的代码中。解释代码时,您也可能会得到用户的积极反馈/赞成。
        • 感谢@AmitVerma 的建议。我已经相应地修改了我的答案。
        • 几个月后,我很欣赏这个解释(具体来说,“我们基本上是从 [M-L] 开始的”)。我不明白为什么像this one 这样的答案对于第二个参数有多个范围。现在我明白了,它基本上是一个扩展。
        【解决方案6】:

        不使用 tr,移动 1 到 25 个字符 并且可以使用26-原始密钥解密

        #!/bin/bash
        
        #set -x
        
        i=0
        for letters in {A..Z}
        do
        abc_cap[$i]="$letters"
        ((i++))
        done
        
        i=0
        for letters in {a..z}
        do
        abc_small[$i]="$letters"
        ((i++))
        done
        
        read -r -p "Enter message to be encrypted/decrypted: " -a message
        read -r -p "Enter shift amount (26 - orig key for decrypt): " shift_amount
        
        echo -n "Encrypted message: "
        
        if [ "$shift_amount" -gt 25 ] || [ "$shift_amount" -lt 1 ]
        then  
        echo "Shift amount out of range"
        exit  
        fi  
        
        for word in "${message[@]}"
        do
         
        while read -r -n 1 letter
        do
        if [[ "$letter" = [a-z] ]]
        then
                for a in "${!abc_small[@]}"
                do
                if [ "${abc_small[$a]}" = "$letter" ]
                then
                a=$(echo "($a + $shift_amount) % 26" | bc)
                echo -n "${abc_small[$a]}"
                fi
                done
        
        elif [[ "$letter" = [A-Z] ]]
        then
                for a in "${!abc_cap[@]}"
                do
               if [ "${abc_cap[$a]}" = "$letter" ]
                then
                a=$(echo "($a + $shift_amount) % 26" | bc)
                echo -n "${abc_cap[$a]}"
                fi
                done
        
        elif [[ "$letter" = "" ]]
        then echo -n " "
         
        else echo -n "$letter"
        fi
         
        done < <(echo "$word")
        done
        echo
        exit
         
        

        【讨论】:

          猜你喜欢
          • 2016-01-10
          • 2020-08-11
          • 2023-03-19
          • 1970-01-01
          • 2019-07-01
          • 1970-01-01
          • 1970-01-01
          • 2016-01-01
          • 2022-08-09
          相关资源
          最近更新 更多