본문 바로가기
내일배움 정리/JS 문법 공부

아스키코드 변환

by GREEN나무 2024. 12. 24.
728x90

 

 

1. 문자 → 아스키코드

charCodeAt(index): 특정 위치의 문자의 아스키코드를 반환합니다.

let char = "A";
let asciiCode = char.charCodeAt(0); // "A"의 아스키코드
console.log(asciiCode); // 65

2. 문자열 → 아스키코드 배열

문자열의 각 문자를 아스키코드로 변환하여 배열로 저장합니다.
방법: split 또는 전개 연산자 [...string]을 사용한 후 map으로 변환.

let str = "Hello";
let asciiArray = [...str].map((char) => char.charCodeAt(0));
console.log(asciiArray); // [72, 101, 108, 108, 111]

3. 아스키코드 → 문자

String.fromCharCode(...codes): 숫자(아스키코드)를 문자로 변환합니다.

let asciiCode = 72;
let char = String.fromCharCode(asciiCode);
console.log(char); // "H"

4. 아스키코드 배열 → 문자열

아스키코드 배열을 하나의 문자열로 변환합니다.
방법: 배열에 String.fromCharCode를 사용하여 문자 배열로 변환 후 결합.

let asciiArray = [72, 101, 108, 108, 111];
let str = asciiArray.map((code) => String.fromCharCode(code)).join("");
console.log(str); // "Hello"

전체 예시

아래는 위의 모든 단계를 하나의 함수로 구현한 예제입니다.

function asciiExample(inputString) {
    // 1. 문자 → 아스키코드
    let singleChar = inputString[0];
    let asciiCode = singleChar.charCodeAt(0);

    // 2. 문자열 → 아스키코드 배열
    let asciiArray = [...inputString].map((char) => char.charCodeAt(0));

    // 3. 아스키코드 → 문자
    let charFromAscii = String.fromCharCode(asciiCode);

    // 4. 아스키코드 배열 → 문자열
    let stringFromAsciiArray = asciiArray.map((code) => String.fromCharCode(code)).join("");

    return {
        asciiCode,
        asciiArray,
        charFromAscii,
        stringFromAsciiArray,
    };
}

// 테스트 실행
let result = asciiExample("Hello");
console.log(result);
/*
{
  asciiCode: 72,                  // 첫 번째 문자의 아스키코드
  asciiArray: [72, 101, 108, 108, 111], // 문자열의 아스키코드 배열
  charFromAscii: "H",             // 아스키코드로부터 문자
  stringFromAsciiArray: "Hello"   // 아스키코드 배열로부터 문자열
}
*/

추가적인 설명

  1. 아스키코드의 범위:
    • 소문자: 97~122 (예: a=97, z=122)
    • 대문자: 65~90 (예: A=65, Z=90)
    • 숫자: 48~57 (예: 0=48, 9=57)
  2. 활용 사례:
    • 암호화: 아스키코드 변환 후 특정 규칙으로 수정.
    • 문자열 비교: 알파벳 순서를 판단하거나 대소문자 변환.

아스키코드를 기반으로 특정 문자열을 암호화하는 알고리즘을 설계 방식

문자열 암호화를 위해 아스키코드 기반 알고리즘을 설계할 때 다음 방식을 사용할 수 있습니다:

  1. 시저 암호 (문자 이동)
    • 각 문자의 아스키코드 값을 일정량(n) 이동시키는 방식.
    • 대소문자를 구분하고, 범위를 벗어날 경우 순환 처리.
    function caesarCipher(str, n) {
        return [...str]
            .map((char) => {
                let charCode = char.charCodeAt(0);
    
                // 소문자 처리
                if (charCode >= 97 && charCode <= 122) {
                    return String.fromCharCode(((charCode - 97 + n) % 26) + 97);
                }
                // 대문자 처리
                if (charCode >= 65 && charCode <= 90) {
                    return String.fromCharCode(((charCode - 65 + n) % 26) + 65);
                }
                // 특수 문자나 공백은 그대로 반환
                return char;
            })
            .join("");
    }
    
    console.log(caesarCipher("Hello World!", 3)); // "Khoor Zruog!"
    
  2. XOR 암호화
    • 각 문자의 아스키코드와 비밀 키 값을 XOR 연산으로 암호화. 복호화 시에도 같은 키를 사용.
    • 암호화 강도는 키값의 복잡성에 따라 달라집니다.
    function xorCipher(str, key) {
        return [...str]
            .map((char) => String.fromCharCode(char.charCodeAt(0) ^ key))
            .join("");
    }
    
    let encrypted = xorCipher("Hello", 42);
    let decrypted = xorCipher(encrypted, 42);
    console.log(encrypted); // 암호화된 문자열
    console.log(decrypted); // "Hello"
    
  3. 난수 기반 암호화
    • 문자의 아스키코드를 무작위 값으로 변환 후 키값과 함께 저장.
    • 복호화를 위해 반드시 키값이 필요.
    function randomEncrypt(str) {
        let key = [...str].map(() => Math.floor(Math.random() * 100));
        let encrypted = [...str].map((char, i) => char.charCodeAt(0) + key[i]);
        return { encrypted, key };
    }
    
    function randomDecrypt(encrypted, key) {
        return encrypted.map((code, i) => String.fromCharCode(code - key[i])).join("");
    }
    
    let { encrypted, key } = randomEncrypt("Hello");
    let decrypted = randomDecrypt(encrypted, key);
    console.log(encrypted, key); // 암호화된 코드와 키
    console.log(decrypted); // "Hello"
    

단순 암호화에는 시저 암호와 XOR이 적합하며, 난수 기반은 더 높은 보안성을 제공합니다.


유니코드 문자(예: 한글, 이모지)의 처리

유니코드 문자를 처리하려면 다음을 고려해야 합니다:

  1. 아스키코드와 유니코드의 차이
    • 아스키코드는 0~127 범위(1바이트)지만, 유니코드는 훨씬 큰 범위를 포함합니다.
    • 예: 한글은 0xAC00~0xD7A3, 이모지는 2바이트 이상.
  2. 유니코드의 가변 길이
    • 이모지나 복합 문자는 여러 코드포인트로 구성될 수 있으므로, charCodeAt 대신 codePointAt 사용이 필요.
    let emoji = "😊";
    console.log(emoji.codePointAt(0)); // 128522
    
  3. 복합 문자 처리
    • Normalization이 필요할 수 있음(예: 한글 조합형 가는 단일 문자와 조합 문자가 있음).
  4. 암호화/복호화에서 올바른 순환
    • 유니코드의 범위는 불규칙적이므로, 특정 범위를 설정하거나 직접 매핑 테이블을 만들어야 합니다.

예제: 한글 처리

function encryptKorean(str, n) {
    return [...str]
        .map((char) => {
            let code = char.charCodeAt(0);

            // 한글 유니코드 범위 처리
            if (code >= 0xAC00 && code <= 0xD7A3) {
                return String.fromCharCode(((code - 0xAC00 + n) % 11172) + 0xAC00);
            }
            return char; // 한글이 아니면 그대로 반환
        })
        .join("");
}

console.log(encryptKorean("안녕하세요", 3)); // "앋녕핟아옇"

 

유니코드 처리를 위해선 codePointAt과 유니코드 범위에 대한 이해가 필요합니다.

 

 

한글과 이모지를 동시에 암호화하면서 범위 충돌을 방지하는 방법

한글과 이모지를 동시에 암호화하려면, 두 가지 과제를 해결해야 합니다:

  1. 범위 구분
    • 한글(0xAC00~0xD7A3)과 이모지(다양한 유니코드 블록)에 대해 각각의 범위를 구분하고 처리해야 합니다.
    • 범위가 겹치지 않도록 특정 기준을 설정하여 고유한 변환 로직을 적용합니다.
  2. 암호화 일관성 유지
    • 서로 다른 범위의 문자를 암호화해도 일관된 복호화가 가능하도록 설계합니다.

설계 아이디어

  1. 범위 기반 분리
    • 입력된 문자의 유니코드 값을 확인하여 한글, 이모지, 기타 문자로 분리합니다.
    • 각 범위에 대해 다른 암호화 로직을 적용합니다.
  2. 범위 내 암호화
    • 범위를 벗어나지 않도록 % 연산으로 순환 처리.
    • 예: 한글은 11172(한글 글자 수), 이모지는 특정 범위로 순환.
  3. 범위 태깅
    • 암호화된 값을 복호화할 때 어떤 범위에서 변환된 것인지 알 수 있도록 태그를 추가합니다.

예제 코드

function encryptText(input, n) {
    return [...input]
        .map((char) => {
            let code = char.codePointAt(0);

            // 한글 처리
            if (code >= 0xAC00 && code <= 0xD7A3) {
                // 한글은 0xAC00을 기준으로 순환
                return String.fromCharCode(((code - 0xAC00 + n) % 11172) + 0xAC00);
            }
            
            // 이모지 처리 (대표적 범위만 예로 설정)
            if ((code >= 0x1F600 && code <= 0x1F64F) || // Smileys
                (code >= 0x1F300 && code <= 0x1F5FF)) { // Miscellaneous
                return String.fromCodePoint(((code - 0x1F600 + n) % 80) + 0x1F600);
            }

            // 기타 문자 처리
            return char; // 변환하지 않고 그대로 반환
        })
        .join("");
}

function decryptText(input, n) {
    return [...input]
        .map((char) => {
            let code = char.codePointAt(0);

            // 한글 복호화
            if (code >= 0xAC00 && code <= 0xD7A3) {
                return String.fromCharCode(((code - 0xAC00 - n + 11172) % 11172) + 0xAC00);
            }
            
            // 이모지 복호화
            if ((code >= 0x1F600 && code <= 0x1F64F) || 
                (code >= 0x1F300 && code <= 0x1F5FF)) {
                return String.fromCodePoint(((code - 0x1F600 - n + 80) % 80) + 0x1F600);
            }

            // 기타 문자 복호화
            return char;
        })
        .join("");
}

// 테스트
let originalText = "안녕하세요 😊🌍";
let encrypted = encryptText(originalText, 3);
let decrypted = decryptText(encrypted, 3);

console.log("Original:", originalText); // 안녕하세요 😊🌍
console.log("Encrypted:", encrypted); // 암호화된 결과
console.log("Decrypted:", decrypted); // 안녕하세요 😊🌍

코드 동작 설명

  1. 한글 처리
    • 한글 유니코드 범위(0xAC00~0xD7A3) 내에서만 순환 처리.
    • 글자 수는 11172자이며, char - 0xAC00로 0부터 시작해 이동 후 복원.
  2. 이모지 처리
    • 대표적인 이모지 유니코드 범위(예: 0x1F600~0x1F64F)를 대상으로 순환 처리.
    • char - 시작점으로 0부터 시작하여 범위를 넘지 않게 % 연산.
  3. 기타 문자 처리
    • 한글과 이모지 범위 외의 문자(영어, 숫자 등)는 그대로 반환.
  4. 복호화
    • 암호화 시와 동일한 로직에서 + n 대신 - n을 적용.
    • % 연산으로 음수 값을 처리하여 올바른 복원.

주의 사항

  1. 이모지 범위
    • 이모지는 다양한 유니코드 블록에 걸쳐 있어 정확한 범위를 지정해야 함.
    • 범위를 명확히 설정하지 않으면 예상치 못한 문자가 처리될 수 있음.
  2. 성능
    • codePointAt과 fromCodePoint는 다중 바이트 문자를 처리하지만, 배열 변환으로 성능이 낮아질 수 있음.
  3. 복합 문자
    • 조합형 한글이나 이모지의 복합 형태(예: 🤷‍♂️)는 추가 처리가 필요할 수 있음.

찾아보기

한글 외 다른 언어(예: 일본어, 중국어)에도 동일한 방식으로 암호화를 적용하려면 어떤 점을 고려해야 할까요?
이모지나 특수 문자의 범위를 더 안전하게 처리하려면 어떤 방법으로 유니코드 블록을 확장할 수 있을까요?

 


아스키코드 배열에서 범위를 벗어나는 숫자를 처리하는 방법

아스키코드 배열을 처리할 때, 범위를 벗어나는 숫자(예: 256 이상의 값)는 다음과 같은 방법으로 해결할 수 있습니다:

  1. 순환 처리 (% 연산)
    • 값이 일정 범위를 초과하면 나머지를 사용해 순환적으로 처리합니다.
    let code = 200;
    let wrapped = code % 128; // 0~127 범위로 순환
    console.log(wrapped); // 72
    
  2. 범위 클램핑 (Clamping)
    • 값을 특정 최소/최대 범위로 제한합니다.
    function clamp(value, min, max) {
        return Math.max(min, Math.min(value, max));
    }
    
    let clamped = clamp(150, 0, 127); // 최대값을 127로 제한
    console.log(clamped); // 127
    
  3. 오류 처리
    • 범위를 벗어나는 값을 발견했을 때 예외를 발생시키거나 기본값으로 설정.
    function handleOutOfRange(code) {
        if (code < 0 || code > 127) throw new Error("Invalid ASCII Code");
        return code;
    }
    
    try {
        console.log(handleOutOfRange(150)); // 오류 발생
    } catch (error) {
        console.error(error.message);
    }
    
  4. 범위 기반 커스텀 로직
    • 문자 범위에 따라 다른 방식으로 처리.
    let code = 150;
    if (code > 122) code -= 26; // 소문자 기준 순환
    console.log(String.fromCharCode(code)); // 변환된 문자
    

범위를 벗어나는 값은 순환(%), 클램핑, 또는 커스텀 로직으로 처리 가능합니다.


 


시저함수

https://ashen99.tistory.com/484

더보기

대 소문자 유지

1. 소문자 처리 코드

let charCode = "a".charCodeAt(0); // 97 
let n = 2; 
let result = String.fromCharCode(((charCode - 97 + n) % 26) + 97); 
console.log(result); // "c"
if (charCode >= 97 && charCode <= 122) {
  return String.fromCharCode(((charCode - 97 + n) % 26) + 97);
}
  1. 조건 확인 (charCode >= 97 && charCode <= 122)
    • charCode가 소문자 알파벳의 아스키코드 범위(97~122)에 있는지 확인.
    • 예: a=97, z=122.
  2. 문자를 0~25 범위로 변환 (charCode - 97)
    • 소문자의 아스키코드를 97을 기준으로 0부터 시작하는 숫자로 변환.
    • 예: a=0, b=1, ..., z=25.
  3. 시프트(+ n)
    • 변환된 숫자에 n(주어진 이동 값)을 더해 새로운 위치를 계산.
    • 예: a(0)에서 n=2를 더하면 2가 되어 c로 이동.
  4. 순환 처리 (% 26)
    • 26으로 나눈 나머지를 사용해 범위를 벗어나지 않도록 순환.
    • 예: z(25)에서 n=2를 더하면 27이 되는데, 27 % 26 = 1로 순환하여 b로 변환.
  5. 아스키코드로 복원 (+ 97)
    • 다시 원래 소문자 범위로 복원하기 위해 97을 더함.
    • 예: 0이 a가 되고, 25가 z가 됨.
  6. 문자 반환 (String.fromCharCode)
    • 최종 계산된 아스키코드를 문자로 변환해 반환.

2. 대문자 처리 코드

let charCode = "Z".charCodeAt(0); // 90
let n = 2;
let result = String.fromCharCode(((charCode - 65 + n) % 26) + 65);
console.log(result); // "B"
if (charCode >= 65 && charCode <= 90) {
  return String.fromCharCode(((charCode - 65 + n) % 26) + 65); 
}
  1. 조건 확인 (charCode >= 65 && charCode <= 90)
    • charCode가 대문자 알파벳의 아스키코드 범위(65~90)에 있는지 확인.
    • 예: A=65, Z=90.
  2. 0~25 범위로 변환 (charCode - 65)
    • 대문자의 아스키코드를 65를 기준으로 0부터 시작하는 숫자로 변환.
    • 예: A=0, B=1, ..., Z=25.
  3. 시프트(+ n)
    • 변환된 숫자에 n을 더해 새로운 위치를 계산.
    • 예: A(0)에서 n=3을 더하면 3이 되어 D로 이동.
  4. 순환 처리 (% 26)
    • 26으로 나눈 나머지를 사용해 범위를 벗어나지 않도록 순환.
    • 예: Z(25)에서 n=2를 더하면 27이 되고, 27 % 26 = 1로 순환하여 B로 변환.
  5. 아스키코드로 복원 (+ 65)
    • 다시 원래 대문자 범위로 복원하기 위해 65를 더함.
    • 예: 0이 A가 되고, 25가 Z가 됨.
  6. 문자 반환 (String.fromCharCode)
    • 최종 계산된 아스키코드를 문자로 변환해 반환.

 

 


cf.

아스키코드 ↔ 문자

: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt

 

문자    아스키코드

: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode

 

'내일배움 정리 > JS 문법 공부' 카테고리의 다른 글

숫자타입  (1) 2024.12.25
isNaN  (0) 2024.12.25
js 코드 최적화  (0) 2024.12.21
알파벳 대소문자 변경  (1) 2024.12.20
캔버스(canvas)를 이용한 도형 그리기  (0) 2024.12.19