회고록 블로그

[공부 필기] JavaScript 문법 공부 25일차 (1) 본문

2. 프로그래밍 언어 공부/JavaScript

[공부 필기] JavaScript 문법 공부 25일차 (1)

김간장 2022. 5. 26. 16:00

※ 필자는 초초초보자입니다.

※ 틀린 내용에 대한 피드백은 언제든지 환영합니다.

 

 

공부하고 있는 자료 : modern JavaScript tutorial 

https://ko.javascript.info/string

 

문자열

 

ko.javascript.info

 

✅ 문자열

- 페이지의 인코딩 방식과 상관없이 자바스크립트에서 문자열은 UTF-16 형식에 따른다.

- 작은따옴표, 큰따옴표, 백틱으로 문자열을 감쌀 수 있는데

   백틱은 감싼 문자열 중간에 표현식을 삽입할 수 있다. (= 템플릿 리터럴이라고 부른다)

   ► 백틱은 여러 줄에 걸쳐 작성할 수도 있다.

 

- 템플릿 함수에서도 백틱이 사용된다.

   ► 백틱 바로 앞에 함수 이름을 쓰면 백틱 안의 문자열 조각/표현식 평가 결과를 인수로 받아 함수가 호출된다고 한다.

function showMessage(message) {
	alert(message);
}

console.log(showMessage`Hello World!`);

- 이런 기능을 태그드 템플릿(tagged template)이라고 한다.

   ► 사용자 지정 템플릿에 맞는 문자열을 쉽게 만들 수 있다고 한다.

   ► 하지만 자주 사용되지는 않는다고..

 

✅ 특수 기호

- 줄바꿈 : \n

- 따옴표 \', \"

- \uXXXX : UTF-16 인코딩 규칙을 사용하는 유니코드 기호 (\u00A9는 저작권 기호의 유니코드이다)

- \u{X...XXXXXX} : X는 1개~6개 사이의 16진수 글자가 올 수 있다. (\u{1F60D} 등)

 

✅ 문자열의 길이

 - length 프로퍼티에 문자열의 길이가 저장된다.

   ► length는 프로퍼티이다. 함수가 아니다.

 

✅ 특정 글자에 접근하기

- [pos] 혹은 charAt(pos) 메서드를 이용해서 특정 글자에 접근할 수 있다.

- 위치는 0부터 시작

   ► 그렇기 때문에 str.length를 대괄호 안에 넣으면 안된다.. (0부터 시작이기 때문에)

let str = "Hello World!";

console.log(str[0]); // H
console.log(str.charAt(1)); // e

console.log(str[str.length]); // undefined
console.log(str[str.length - 1]); // !

 

- for...of 를 사용하면 문자열의 각 글자(char)를 대상으로 어떠한 작업을 할 수 있다.

"use strict";

let str = "Hello World!";
let indexNum = 1;

for (let char of str) {
	console.log(`${indexNum} : ${char}`);
	indexNum++;
}

 

✅ 문자열의 불변성

- 처음 자바스크립트를 공부할 때 배웠던 것처럼 함수형 언어이므로 문자열을 수정할 수 없다.

- 함수형 프로그래밍 언어는 [변수값 변경을 금지]하는 특징이 있다.
- 일단 변수 이름이 붙은 상자 속에 저장되면, 그 값을 영원히 유지하게 되고
   다른 값을 저장하고 싶으면 새로운 상자(새로운 변수)를 만들어야 한다.
- 즉, 이전 변수를 재사용할 수 없다.

 

- 따라서, 문자열의 일부만 변경하는 것도 불가능하다.

- 대신 새로운 문자열을 하나 만든 다음 변수에 할당할 수는 있다.

 

✅ 대.소문자 변경하기

- toLowerCase() 와 toUpperCase() 메서드는 대.소문자를 변경해주는 메서드이다.

- 이 또한 결국 새로운 문자열을 하나 만드는 것이다.

 

- 전체를 변경하거나, 하나의 글자만 변경할 수도 있다.

"use strict";

let str = "Hello World!";

console.log(str.toUpperCase()); //HELLO WORLD!
console.log(str[0].toLowerCase()); // h

 

✅ 부분 문자열(substring) 찾기

- 첫번째 방법 : str.indexOf 메서드 이용하기

- 두번째 방법 : str.lastIndexOf 메서드 이용하기

- 세번째 방법 : 비트 NOT 연산자(~) 사용하기

   ► NOT 연산자는 32비트 정수로 바꾸고 모든 비트를 반전한다.

   ► ~n-(n+1)이 된다.

let str = "Widget";

if (~str.indexOf("Widget")) {
  alert( '찾았다!' ); // 의도한 대로 동작합니다.
}

// 코드출처 : 모던 자바스크립트 (https://ko.javascript.info/string)

- 네번째 방법 : includes, startsWith, endsWith

   ► str.includes 메서드, str.startsWith 메서드, str.endsWith 메서드를 이용한다.

   ► startsWith는 문자열 str이 특정 문자열로 시작하는지 여부 확인

   ► endsWith는 문자열 str이 특정 문자열로 끝나는지 여부 확인

 

✅ 부분 문자열(substring) 추출하기

- 첫번째 방법 : str.slice(start [, end]) 메서드 이용하기

- 두번째 방법 : str.substring[start [, end]) 메서드 이용하기

- 세번째 방법 : str.substr(start [, length]) 메서드 이용하기

   ► substr은 브라우저 이외의 호스트 환경에서는 제대로 동작하지 않을 수도 있다.

 

✅ utf-16 인코딩 기준, 코드(code)로 글자 얻기

- 첫번째 방법 : str.codePointAt(pos) : 코드 알아낼 수 있다.

- 두번째 방법 : String.fromCodePoint(code) : 코드에 대응하는 글자를 만들어준다.

- 세번째 방법 : \uXXXX

 

✅ 문자열 제대로 비교하기

- 문자열을 제대로 비교하는 알고리즘을 만드는건 생각보다 간단하지 않다.

- 문자열을 제대로 비교하려면 일단 페이지에서 어떤 언어를 사용하고 있는지 브라우저가 알아야 한다.

   ► 현재의 대부분의 브라우저는 국제화 관련 표준 ECMA-402를 지원한다

   ► IE10은 Intl.js 라이브러리를 사용해야한다

 

- ECMA-402에 언어가 다를 때 적용할 수 있는 문자열 비교 규칙과 이를 준수하는 메서드가 정의되어있다.

   ► str.localeCompare(str2)

- str.localCompare(str2)

   ► str이 str2보다 작은지, 같은지, 큰지를 나타내주는 정수가 반환된다.

   ► 파라미터에 대한 자세한 설명은 MDN을 참고할 것

(https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare)

 

✅ 서로게이트 쌍

- 자주 사용되는 글자는 모두 2바이트 코드를 가지고 있다.

- 하지만 2바이트는 65,536(2의16승)개의 조합 밖에 만들어내지 못하기 때문에 모든 기호를 표현하기에는 부족하다.

   ► 이를 극복하려고 나온 것이 '서로게이트 쌍(surrogate pair)'이라고 한다.

- 쉽게말해서 2바이트 글자들의 쌍을 사용해 인코딩하는 것이라고 한다.

   ► 때문에 글자수는 2개가 된다.

console.log('a'.length); // 1
console.log('🥺'.length); // 2

 

- 서로게이트 쌍은 두 개의 글자가 붙어있을 때만 의미있는 기호가 되고 각각을 출력하면 이상한 값이 출력된다.

console.log('🥺'[0]);  // �
console.log('🥺'[1]);  // �

 

- 참고로 String.fromCodePoint와 str.codePointAt은 서로게이트 쌍을 처리하지 못한다.

 

 

- 서로게이트 쌍(surrogate pair)는 두 개의 글자로 되어 있는데 각각의 글자에 대한 코드(code)를 출력해보면 다음과 같다.

   ► 보기편하게 16진수로 바꿔서 출력하였다.

   ► 두 글자이기 때문에 세번째, 네번째 char(문자)는 NaN이 출력된다.

console.log('🥺'.charCodeAt(0).toString(16)); //d83e
console.log('🥺'.charCodeAt(1).toString(16)); //dd7a
console.log('🥺'.charCodeAt(2).toString(16)); //NaN
console.log('🥺'.charCodeAt(3).toString(16)); //NaN

- 사실 서로게이트 쌍(surrogate pair)의 각 글자(char)는 코드의 범위가 정해져있다.

   ► 첫번째 글자(char)의 코드는 0xd800과 0xdbff 사이가 되며

   ► 두번째 글자(char)의 코드는 0xdc00과 0xdfff 사이가 된다.

   ► 이는 표준에서 서로게이트 쌍을 위해 일부러 비워둔 코드들이라고 한다.

 

✅ 발음 구별 기호, 유니코드 정규화

- a를 베이스 글자로 한 다양한 기호(à, á, â, ä 등)는 어떻게 코드로 표현될까

- 이런 합성 글자들은 대부분 UTF-16 테이블에서 독자적인 코드를 가지지만

   워낙 조합 가능한 글자의 수가 많아서 모든 합성 글자가 독자적인 코드를 갖고 있는 것은 아니다.

 

- 그래서 베이스 글자 뒤에 하나 또는 여러 개의 유니코드 문자를 붙여서 사용할 수 있도록 만들었다.

   ► 아래의 코드는 베이스 글자 a의 뒤에 윗 점을 나타내는 유니코드 문자(\u0307)을 붙여 만든 것이다.

"use strict";

console.log('a\u0307'); //ȧ

 

- 하지만 베이스 글자 뒤에 여러 개의 유니코드 문자를 붙이다보면

   사람이 보기에는 같아 보여도 동등 비교할 때는 다른 경우가 있다.

"use strict";

let char1 = 'a\u0307\u0323';
let char2 = 'a\u0323\u0307';

if (char1 === char2) console.log("같다");
else console.log("다르다");

// 출력 결과 : 다르다

 

- 이러한 문제를 해결하기 위해 [유니코드 정규화] 알고리즘을 사용한다.

   ► 각 문자열을 동일한 형태로 정규화하는 것

   ► 이 알고리즘은 str.normalize 메서드에 구현되어 있다.

   ► normalize에 의해 세 개의 글자가 하나로 합쳐진다. 

"use strict";

let char1 = 'a\u0307\u0323'.normalize();
let char2 = 'a\u0323\u0307'.normalize();

if (char1 === char2) console.log("같다");
else console.log("다르다");

// 출력 결과 : 같다

 

- 다만 이렇게 정규화가 가능한것은 세 개의 글자를 합쳐져서 만들어진 [하나의 글자]가 UTF-16 테이블에 정의되어 있기 때문이다.

   /* 아마 세 개의 글자를 합쳐서 만들어진 하나의 글자가 테이블에 정의되어 있지 않으면 무슨 글자인지 인식하지 못할 것 같다. */

 

 

Comments