programmers 코딩테스트 : 시저 암호

H·2022년 5월 18일
1

Coding Test

목록 보기
17/26

🔔 시저 암호

📢 문제 설명
어떤 문장의 각 알파벳을 일정한 거리만큼 밀어서 다른 알파벳으로 바꾸는 암호화 방식을 시저 암호라고 합니다. 예를 들어 "AB"는 1만큼 밀면 "BC"가 되고, 3만큼 밀면 "DE"가 됩니다. "z"는 1만큼 밀면 "a"가 됩니다. 문자열 s와 거리 n을 입력받아 s를 n만큼 민 암호문을 만드는 함수, solution을 완성해 보세요.

⛔ 제한 조건
공백은 아무리 밀어도 공백입니다.
s는 알파벳 소문자, 대문자, 공백으로만 이루어져 있습니다.
s의 길이는 8000이하입니다.
n은 1 이상, 25이하인 자연수입니다.


🔠 통과한 코드

const s = "a B z"
const n = 4;
//다른 케이스 확인
//const s = "p";
//const n = 15;
solution(s, n);
function solution(s, n) {
    let num = 0;
    let str = "";
    let answer = "";
    let answerArr = [];
    let arr = s.length > 1 ? s.split("") : s;
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === " ") {
            str = " ";
        }
        //z,Z 케이스
        else if (arr[i] === "z" || arr[i] === "Z") {
            let newNum = arr[i].charCodeAt(0);
            let newStr = String.fromCharCode(
                newNum - ("Z".charCodeAt(0) - "A".charCodeAt(0)) + n - 1
            );
            str = newStr;
        } else {
            num = arr[i].charCodeAt(0) + n;
            if (num < "Z".charCodeAt(0) && num < "z".charCodeAt(0)) {
                //제일 큰 수를 기준으로 작은 경우에만 num 정상 출력
                str = String.fromCharCode(num);
            } else {
                if (arr[i] === arr[i].toLowerCase()) {
                    //대소문자 구별해서 소문자 케이스
                    str =
                        num > "z".charCodeAt(0)
                            ? String.fromCharCode(
                                "a".charCodeAt(0) + (num - "z".charCodeAt(0) - 1)
                            )
                            : String.fromCharCode(num);
                } else {
                    str =
                        num > "Z".charCodeAt(0)
                            ? String.fromCharCode(
                                "A".charCodeAt(0) + (num - "Z".charCodeAt(0) - 1)
                            )
                            : String.fromCharCode(num);
                }
            }
        }

        answerArr.push(str);
    }
    answer = answerArr.join("");
    return answer;
}

📌 코드 설명

  1. 문자열 (s)의 길이가 1 이상일 때 배열, 아닌 경우 arr로 선언한다.

  2. for문으로 arr[i]번째에 공백이 있는 경우, 해당 공백은 아스키 코드로 변환하지 않는다.

  3. 조건1
    arr[i]가 z,Z 인 경우 n = 1 이상일 때 z + n의 문자열은 'a'부터 시작된다.

  4. 해당 arr[i]의 charCodeAt() 구한다.

  5. z > a 순으로 시작해야되기 때문에 a 부터 시작하고, n을 더한 후 -1 한다.
    "z".charCodeAt(0) - "a".charCodeAt(0) + n - 1

  6. 조건2

    1. num = arr[i].charCodeAt(0) + n; 해당 배열에 맞게 구해줌
    2. 조건 2-1
      1. 소문자, 대문자 기준 Z,z의 아스키코드 번호(제일 큰 수)를 기준으로 위에서 구한 num이 넘치지 않을 떄
        str = String.fromCharCode(num); > 기본 반환
    3. 조건 2-2
      1. 2-1의 조건이 false인 경우 = 알파벳 아스키코드로 설정된 숫자가 넘는 경우
        1. 조건 2-2-1 대소문자 구별하기
          1. arr[i] === arr[i].toLowerCase() 대/소문자 구별
          2. num이 'z'의 아스키코드보다 크다면 조건 1의 2번의 계산식으로 계산함
  7. answerArr.push(str)

  8. answer = answerArr.join("");

  9. return answer;

📌 charCodeAt()
str.charCodeAt(index)
메서드는 주어진 인덱스에 대한 UTF-16 코드를 나타내는 0부터 65535 사이의 정수를 반환합니다.

📌 String.fromCharCode()
String.fromCharCode(num1[, ...[, numN]])
메서드는 UTF-16 코드 유닛의 시퀀스로부터 문자열을 생성해 반환합니다.


🔠 다른 사람의 코드

  function solution(s, n) {
    let chars =
        "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXY                          ";
    return s
        .split("")
        .map((e) => chars[chars.indexOf(e) + n])
        .join("");
}

📌 코드 설명

  1. 알파벳이 담긴 배열을 만든다 두번씩 적어서 z가 a로 돌아가도 괜찮음
  2. 배열을 map()으로 꺼내서 chars.indexOf(e)로 위치를 찾는다.
  3. e+n
  4. join('');
  5. return answer;

🔠 다른 사람의 코드

 function solution(s, n) {
    let upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    let lower = "abcdefghijklmnopqrstuvwxyz";
    let answer = "";

    for (let i = 0; i < s.length; i++) {
        let text = s[i];
        if (text == " ") {
            answer += " ";
            continue;
        }
        let textArr = upper.includes(text) ? upper : lower;
        let index = textArr.indexOf(text) + n;
        if (index >= textArr.length) index -= textArr.length;
        answer += textArr[index];
    }
    return answer;
}

📌 코드 설명

  1. 소문자, 대문자 배열을 만든다
  2. for문으로 문자열 s길이만큼 i를 돌림 s의 index는 text;
  3. text가 " "면 answer += " " //공백 수 만큼 돌리기 continue;
  4. let textArr = upper.includes(text) ? upper : lower; //text가 있는지 없는지로 소문자인지 대문자인지 비교
  5. let index = textArr.indexOf(text) + n; //배열에서 text index + n
  6. 해당 알파벳 배열과 index가 같거나 넘으면 textArr.length (26) - index(+n된 수) 반복
  7. testArr[index]의 모든 index 꺼내기
  8. return answer;

🍀 피드백

function solution(s, n) {
    let answer = "";
    const upperMinAscii = 65;
    const upperMaxAscii = 90;
    const lowerMinAscii = 97;
    const lowerMaxAscii = 122;
    const asciiArray = Array.from(s).map((item) => {
        let ascii = item.charCodeAt(0);
        const isWhite = item === " ";
        if (isWhite) {
            return ascii;
        }
        const isNotAlpahbet =
            !(ascii >= upperMinAscii && ascii <= upperMaxAscii) &&
            !(ascii >= lowerMinAscii && ascii <= lowerMaxAscii);
        if (isNotAlpahbet) {
            return ascii;
        }
        const isUpper = ascii < lowerMinAscii;
        const min = isUpper ? upperMinAscii : lowerMinAscii;
        const max = isUpper ? upperMaxAscii : lowerMaxAscii;
        ascii += n;
        if (ascii > max) {
            return (ascii % max) + min - 1;
        }
        return ascii;
    });
    answer = String.fromCharCode.apply(null, asciiArray);
    console.log(answer);
    return answer;
}

📌 apply()
func.apply(thisArg, [argsArray])
주어진 this 값과 배열(또는 유사 배열객체)로 제공되는 arguments로 함수를 호출합니다.
📍 thisArg : func을 호출하는데 제공될 this의 값. 메소드에 의해 실제로 보여지는 값이 아닐 수 있음 주의 !
메소드가 non-strict mode 코드의 함수일 경우, nullundefined가 전역 객체로 대체 되며, 기본 값은 제한합니다.
📍 argsArray : func이 호출되어야 하는 인수를 지정하는 유사 배열 객체, 함수에 제공된 인수가 없을 경우 null or undefinded 배열대신 제네릭 유사 배열 객체로 사용 될 수 있음
📍 반환 값 : 지정한
this_값과 인수들로 호풀한 함수의 결과

apply는 지원되는 인수의 타입만 제외하면 call()과 매우 유사합니다. 인수(파라미터)의 리스트 대신 인수들의 배열을 사용할 수 있습니다.
또한 apply를 사용해, 배열 리터럴이나( 예 func.apply(this, ['e','a]), Array 객체 예 (func.apply(this , new Array('e', 'a'))를 사용 할 수 있습니다. args array 파라미터를 위한 argments를 사용 할 수도 있습니다. arguments는 함수의 지역변수 입니다. 이는 호출된 객체의 지정되지 않은 모든 인수에 대해 사용할 수 있습니다.
따라서 apply 메소드를 사용할 때 호출된 객체의 인수를 알 필요가 없습니다. argments를 사용해 모든 인수들을 호출된 객체로 전달 할 수 있습니다. 그럼 호출된 객체는 그 인수들을 처리할 수 있게됩니다.
ECMAscript 5 (chrome 14, ie 9 지원 X):
모든 유사 배열 객체 타입을 사용 할 수 있으며, 실제로 이는 프로퍼티 length와 범위 (0..length-1)내의 정수 프로퍼티를 갖는다는 것을 의미합니다.
예를 들면 이제 nodelist 또는 {'length': 2, '0' : 'e', '1' : 'banana'}와 같은 커스텀 객체를 사용 할 수 있습니다.

📌 answer = String.fromCharCode.apply(null, asciiArray);
null을 사용 한 이유 :
이미 존재하는 함수를 호출할 떄 다른 this 객체를 할당 가능
this는 현재 객체, 호출하는 객체를 참조합니다. apply를 사용해, 새로운 객체마다 다른 객체에 상속시킬 수 있음

apply() 참조 url

profile
🤘 돌머리도 ROCK이다! 🤘

0개의 댓글