JavaScript を使用した Caesar Shift 暗号関数の作成: パート 1


Caesar cipher は暗号化技術です.単語の各文字を取得し、その意味をあいまいにするために、アルファベット順で特定の数だけ前方にシフトします.したがって、次数シフトが 1 の「cab」は「dbc」になります.暗号を送った人は、元の意味に戻すための数値とシフト次数を知っています.
shiftDegreesinputText の 2 つのパラメーターを受け取り、各文字を指定された角度だけ前方にシフトした文字列を返す関数を書きたいと思いました.

だから私はから始めました:

function caesarShift(inputText, shiftDegrees) { 

}


この関数を参照するためのアルファベットも必要だったので、配列を取得しました.

const lowerCaseAlphabet = [
    'a',
    'b',
    'c',
    'd',
    'e',
    'f',
    'g',
    'h',
    'i',
    'j',
    'k',
    'l',
    'm',
    'n',
    'o',
    'p',
    'q',
    'r',
    's',
    't',
    'u',
    'v',
    'w',
    'x',
    'y',
    'z',
]


それでは、エッジケースに注意してください.正直なところ、これらは関数を書き終える頃に思い浮かびましたが、ロジックの一番上に置いたので、今説明しています.私が持っている関数内:

    if (shiftDegrees > 26 || shiftDegrees < -26) {
        return 'use a shift between -26 and 26'
    }


別の解決策は、26 をそれより大きい任意の数の因数として取り、残りを shiftDegree として取ることです.これは私にとってストレッチ ゴールですが、コメントに解決策を追加してください.

他のエッジケースは無効なパラメータでした:

    if (typeof shiftDegrees != 'number') {
        return 'shiftDegree must be a number'
    }
    if (typeof inputText != 'string') {
        return 'inputText must be string'
    }


次に、大文字化の問題を解消する時が来ました.

const inputTextToLowerCase = inputText.toLowerCase()


また、 inputString の各文字のインデックスを取得したいので、この変数を空の配列に設定します.

let arrayOfAlphaIdxes = []


ここで、入力単語の各文字のインデックスを分離するために、いくつかの for ループを実行しました.

    for (let i = 0; i < inputText.length; i++) {
        for (let j = 0; j < lowerCaseAlphabet.length; j++) {
            if (inputTextToLowerCase[i] === lowerCaseAlphabet[j]) {
                arrayOfAlphaIdxes.push(j)
            }
        }
    }


基本的に、これは inputText 文字列の長さを実行し、各文字の各値をアルファベットのインデックスに一致させます.次に、その新しい値を配列 arrayOfAlphaIdxes にプッシュしました.

ここで、これらのインデックスを移動する必要がありました.別の for ループを実行し、それぞれに shiftDegrees を追加して arrayOfMovedAlphaIdxes にプッシュしたため、 arrayOfMovedAlphaIdxes は Caesar-shifted インデックスを表しています.

最後に、新しいインデックスごとに文字の値を取得し、それらを新しい文字列に変換します.

 // for loop that creates an array of new letters with the new shifted indexes
    arrayWithNewLetters = []
    for (let i = 0; i < arrayOfMovedAlphaIdxes.length; i++) {
        for (let j = 0; j < lowerCaseAlphabet.length; j++) {
            if (arrayOfMovedAlphaIdxes[i] === j) {
                arrayWithNewLetters.push(lowerCaseAlphabet[j])
            }
        }
    }


これを行うには、空の配列を作成し、新しい値を double for ループでプッシュして、インデックスの配列とアルファベットから値を取得しました.

パズルの最後のピースは、返す文字列を作成することでした.

    const stringWithCommas = arrayWithNewLetters.toString()

    const removedCommas = stringWithCommas.split(',').join('')

    return removedCommas


この時点で、この関数:

caesarShift('HELLO', 2)


この出力がありました:

jgnnq


これは、関数が必要なものを出力しているように見えますが、より高いシフト度を試してみましょう:

caesarShift('HELLO', 20)


出力:

y


応答が切り捨てられました.インデックスカウントを「ラップアラウンド」、いわばアルファベット配列にするロジックを追加するのを忘れていました.今何をする?さて、私たちの未知数を知りましょう.最初の未知数は、端からの距離です.配列の距離は固定されているため、これを行うことで次のことがわかりました.

 let distanceFromEndIncludingCurrentLetter = 27 - arrayOfAlphaIdxes[i]


これで、shiftDegrees が端からの距離より大きい場合、トリアージを行う必要があることがわかりました.

問題を解決するには? shiftDegrees と最後までの距離の差は、配列を「ループ」するために値を最初からシフトする必要があるインデックスの数であることはわかっています.そのため、そのデルタ shiftDegrees - distanceFromEndIncludingCurrentLetter によって新しいインデックスを割り当てます.

最後に、関数を次のように変更しました.

    //for loop that changes the arrayindex by shift number
    for (let i = 0; i < arrayOfAlphaIdxes.length; i++) {
        let distanceFromEndIncludingCurrentLetter = 27 - arrayOfAlphaIdxes[i]
        if (shiftDegrees < distanceFromEndIncludingCurrentLetter) {
            let newIdx = arrayOfAlphaIdxes[i] + shiftDegrees
            arrayOfMovedAlphaIdxes.push(newIdx)
        } else {
            let differenceBtw =
                shiftDegrees - distanceFromEndIncludingCurrentLetter
            arrayOfMovedAlphaIdxes.push(differenceBtw)
        }
    }


興味があれば、完全なコードは私の Github profile にあります!フィードバックをお待ちしております. ❤️