2 substr() í¹ì Indexìì ìíë 길ì´ë§í¼ ìë¼ì 문ìì´ë¡ 리í´
3 substring() ìì Indexìì ë Index ì ê¹ì§ 문ìì´ì ìë¼ì 리í´
String 메소드
String 메소드
String 메소드는 String 객체에 정의된 문자열과 관련된 작업을 할 때 사용하는 메소드입니다.
1. String.fromCharCode()
2. String.fromCodePoint()
String.fromCharCode() 메소드
이 메소드는 쉼표로 구분되는 일련의 유니코드에 해당하는 문자들로 구성된 문자열을 반환합니다.
예제 String.fromCharCode(65, 66, 67); // “ABC”
String.fromCodePoint() 메소드
이 메소드는 쉼표로 구분되는 일련의 코드 포인트(code point)에 해당하는 문자들로 구성된 문자열을 반환합니다.
예제 String.fromCodePoint(65, 66, 67); // “ABC” String.fromCodePoint(0x2F804); // “\uD87E\uDC04” String.fromCodePoint(194564); // “\uD87E\uDC04”
String.fromCodePoint() 메소드는 사파리, 익스플로러에서 지원하지 않습니다.
자바스크립트 String 메소드
메소드 설명 String.fromCharCode() 쉼표로 구분되는 일련의 유니코드에 해당하는 문자들로 구성된 문자열을 반환함. String.fromCodePoint() 쉼표로 구분되는 일련의 코드 포인트(code point)에 해당하는 문자들로 구성된 문자열을 반환함. String.raw() 템플릿 문자열(template string)의 원형을 반환함.
String.prototype 메소드
모든 String 인스턴스는 String.prototype으로부터 메소드와 프로퍼티를 상속받습니다.
이렇게 상속받은 String.prototype 메소드를 이용하면, 다음과 같은 문자열 작업을 할 수 있습니다.
1. 문자열에서의 위치 반환
2. 문자열에서 지정된 위치에 있는 문자 반환
3. 문자열 추출
4. 문자열 분리
5. 문자열 결합
6. 문자열의 대소문자 변환
7. 문자열 주위의 공백 제거
8. 정규 표현식을 이용한 문자열 조작
String 인스턴스의 값은 변경될 수(immutable) 없으므로, 모든 String 메소드는 결괏값으로 새로운 문자열을 생성하여 반환합니다.
문자열에서의 위치 찾기
다음 메소드는 String 인스턴스에서 특정 문자나 문자열이 처음으로 등장하는 위치나 마지막으로 등장하는 위치를 반환합니다.
– indexOf()
– lastIndexOf()
이 메소드들은 문자열을 찾기 시작할 String 인스턴스의 위치를 두 번째 인수로 전달할 수 있습니다.
만약 전달받은 특정 문자나 문자열을 찾을 수 없을 때는 -1을 반환합니다.
예제 var str = “abcDEFabc”; str.indexOf(‘abc’); // 0 -> 자바스크립트에서 인덱스는 0부터 시작함. str.indexOf(‘abcd’); // -1 -> 문자열을 비교할 때 문자의 대소문자를 구분함. str.indexOf(‘abc’, 3); // 6 -> 인덱스 3부터 ‘abc’를 찾기 시작함. str.lastIndexOf(‘abc’); // 6 str.lastIndexOf(‘d’); // -1 str.lastIndexOf(‘c’); // 8 코딩연습 ▶
문자열에서 지정된 위치에 있는 문자 반환
다음 메소드는 String 인스턴스에서 전달받은 인덱스에 위치한 문자나 문자 코드를 반환합니다.
– charAt()
– charCodeAt()
– charPointAt()
예제 var str = “abcDEFabc”; str.charAt(0); // a str.charAt(10); // 빈 문자열 -> 전달받은 인덱스가 문자열의 길이보다 클 경우에는 빈 문자열을 반환함. str.charCodeAt(0); // 97 -> ‘a’에 해당하는 UTF-16 코드를 반환함. str.codePointAt(0); // 97 -> ‘a’에 해당하는 유니코드 코드 포인트를 반환함. 코딩연습 ▶
codePointAt() 메소드는 사파리, 익스플로러에서 지원하지 않습니다.
문자열 추출
다음 메소드는 String 인스턴스에서 전달받은 시작 인덱스부터 종료 인덱스 바로 앞까지의 문자열만을 추출하여 만든 새로운 문자열을 반환합니다.
– slice()
– substring()
– substr()
예제 var str = “abcDEFabc”; str.slice(2, 6); // cDEF -> 인덱스 2부터 인덱스 5까지의 문자열을 추출함. str.slice(-4, -2); // Fa -> 음수로 전달된 인덱스는 문자열의 뒤에서부터 시작함. str.slice(2); // abcDEFab -> 인수로 종료 인덱스가 전달되지 않으면 문자열의 마지막까지 추출함. str.substring(2, 6); // cDEF str.substr(2, 4); // cDEF 코딩연습 ▶
문자열 분리
다음 메소드는 String 인스턴스를 구분자(separator)를 기준으로 나눈 후, 나뉜 문자열을 하나의 배열로 반환합니다.
– split()
split() 메소드는 인수로 구분자를 전달하지 않으면, 전체 문자열을 하나의 배열 요소로 가지는 길이가 1인 배열을 반환합니다.
예제 var str = “자바스크립트는 너무 멋져요! 그리고 유용해요.”; str.split(); // 구분자를 명시하지 않으면 아무런 동작도 하지 않음. str.split(“”); // 한 문자(“”)씩 나눔. str.split(” “); // 띄어쓰기(” “)를 기준으로 나눔. str.split(“!”); // 느낌표(“!”)를 기준으로 나눔. 코딩연습 ▶
문자열 결합
다음 메소드는 String 인스턴스에 전달받은 문자열을 결합한 새로운 문자열을 반환합니다.
– concat()
예제 var str = “자바스크립트”; str; // 자바스크립트 str.concat(“는 너무 멋져요!”); // 자바스크립트는 너무 멋져요! str.concat(“는 너무 멋져요!”, ” 그리고 유용해요.”); // 자바스크립트는 너무 멋져요! 그리고 유용해요! str; // 자바스크립트 코딩연습 ▶
위의 예제에서 여러 번 concat() 메소드를 실행한 후의 변수 str의 문자열은 여전히 처음과 같습니다.
이처럼 자바스크립트에서 String 인스턴스의 값은 변경될 수(immutable) 없습니다.
따라서 모든 String 메소드는 결괏값으로 새로운 문자열을 생성하여 반환합니다.
문자열의 대소문자 변환
다음 메소드는 String 인스턴스의 모든 문자를 대문자나 소문자로 변환한 새로운 문자열을 반환합니다.
– toUpperCase()
– toLowerCase()
예제 var str = “JavaScript”; str.toUpperCase(); // JAVASCRIPT str.toLowerCase(); // javascript 코딩연습 ▶
문자열 주위의 공백 제거
다음 메소드는 String 인스턴스의 양 끝에 존재하는 모든 공백과 줄 바꿈 문자(LF, CR 등)를 제거한 새로운 문자열을 반환합니다.
– trim()
trim() 메소드는 String 인스턴스의 문자열 값 그 자체에는 영향을 주지 않습니다.
예제 var str = ” JavaScript “; str.trim(); 코딩연습 ▶
정규 표현식을 이용한 문자열 조작
다음 메소드는 인수로 전달받은 정규 표현식을 이용하여, String 인스턴스 값에서 검색, 대조, 대체 등의 작업을 수행합니다.
– search()
– match()
– replace()
정규 표현식에 대한 더 자세한 사항은 자바스크립트 정규 표현식 수업에서 확인할 수 있습니다.
자바스크립트 정규 표현식 수업 확인 =>
자바스크립트 String.prototype 메소드
메소드 설명 indexOf() String 인스턴스에서 특정 문자나 문자열이 처음으로 등장하는 위치의 인덱스를 반환함. lastIndexOf() String 인스턴스에서 특정 문자나 문자열이 마지막으로 등장하는 위치의 인덱스를 반환함. charAt() String 인스턴스에서 전달받은 인덱스에 위치한 문자를 반환함. charCodeAt() String 인스턴스에서 전달받은 인덱스에 위치한 문자의 UTF-16 코드를 반환함. (0 ~ 65535) charPointAt() String 인스턴스에서 전달받은 인덱스에 위치한 문자의 유니코드 코드 포인트(unicode code point)를 반환함. slice() String 인스턴스에서 전달받은 시작 인덱스부터 종료 인덱스 바로 앞까지의 문자열을 추출한 새 문자열을 반환함. substring() String 인스턴스에서 전달받은 시작 인덱스부터 종료 인덱스 바로 앞까지의 문자열을 추출한 새 문자열을 반환함. substr() String 인스턴스에서 전달받은 시작 인덱스부터 길이만큼의 문자열을 추출한 새로운 문자열을 반환함. split() String 인스턴스에서 구분자(separator)를 기준으로 나눈 후, 나뉜 문자열을 하나의 배열로 반환함. concat() String 인스턴스에 전달받은 문자열을 결합한 새로운 문자열을 반환함. toUpperCase() String 인스턴스의 모든 문자를 대문자로 변환한 새로운 문자열을 반환함. toLowerCase() String 인스턴스의 모든 문자를 소문자로 변환한 새로운 문자열을 반환함. trim() String 인스턴스의 양 끝에 존재하는 공백과 모든 줄 바꿈 문자(LF, CR 등)를 제거한 새로운 문자열을 반환함. search() 인수로 전달받은 정규 표현식에 맞는 문자나 문자열이 처음으로 등장하는 위치의 인덱스를 반환함. replace() 인수로 전달받은 패턴에 맞는 문자열을 대체 문자열로 변환한 새 문자열을 반환함. match() 인수로 전달받은 정규 표현식에 맞는 문자열을 찾아서 하나의 배열로 반환함. includes() 인수로 전달받은 문자나 문자열이 포함되어 있는지를 검사한 후 그 결과를 불리언 값으로 반환함. startsWith() 인수로 전달받은 문자나 문자열로 시작되는지를 검사한 후 그 결과를 불리언 값으로 반환함. endsWith() 인수로 전달받은 문자나 문자열로 끝나는지를 검사한 후 그 결과를 불리언 값으로 반환함. toLocaleUpperCase() 영문자뿐만 아니라 모든 언어의 문자를 대문자로 변환한 새로운 문자열을 반환함. toLocaleLowerCase() 영문자뿐만 아니라 모든 언어의 문자를 소문자로 변환한 새로운 문자열을 반환함. localeCompare() 인수로 전달받은 문자열과 정렬 순서로 비교하여 그 결과를 정수 값으로 반환함. normalize() 해당 문자열의 유니코드 표준화 양식(Unicode Normalization Form)을 반환함. repeat() 해당 문자열을 인수로 전달받은 횟수만큼 반복하여 결합한 새로운 문자열을 반환함. toString() String 인스턴스의 값을 문자열로 반환함. valueOf() String 인스턴스의 값을 문자열로 반환함.
연습문제
자바스크립트 String 메소드
String 객체는 원시 타입인 문자열을 다룰 때 유용한 프로퍼티와 메소드를 제공하는 레퍼(wrapper) 객체이다.
변수 또는 객체 프로퍼티가 문자열을 값으로 가지고 있다면 String 객체의 별도 생성없이 String 객체의 프로퍼티와 메소드를 사용할 수 있다.
String Property
String.length
문자열 내의 문자 갯수를 반환한다.
String 객체는 length 프로퍼티를 소유하고 있으므로 유사 배열 객체이다.
const str1 = ‘Hello’; console.log(str1.length); // 5
String Method
String 객체의 모든 메소드는 언제나 새로운 문자열을 반환한다. 문자열은 변경 불가능(immutable)한 원시 값이기 때문이다.
String.prototype.charAt(number) : string
인수로 전달한 index를 사용하여 index에 해당하는 위치의 문자를 반환한다.
index는 0 ~ (문자열 길이 – 1) 사이의 정수이다. 지정한 index가 문자열의 범위(0 ~ (문자열 길이 – 1))를 벗어난 경우 빈문자열을 반환한다.
const str = ‘Hello’; console.log(str.charAt(0)); // H console.log(str.charAt(1)); // e console.log(str.charAt(2)); // l console.log(str.charAt(3)); // l console.log(str.charAt(4)); // o // 지정한 index가 범위(0 ~ str.length-1)를 벗어난 경우 빈문자열을 반환한다. console.log(str.charAt(5)); // ” // 문자열 순회. 문자열은 length 프로퍼티를 갖는다. for (let i = 0; i < str.length; i++) { console.log(str.charAt(i)); } // String 객체는 유사 배열 객체이므로 배열과 유사하게 접근할 수 있다. for (let i = 0; i < str.length; i++) { console.log(str[i]); // str['0'] }
String.prototype.indexOf(searchstring, fromIndex) : number
인수로 전달한 문자 또는 문자열을 대상 문자열에서 검색하여 처음 발견된 곳의 index를 반환한다.
발견하지 못한 경우 -1을 반환한다.
const str = 'Hello World'; console.log(str.indexOf('l')); // 2 console.log(str.indexOf('or')); // 7 console.log(str.indexOf('or' , 8)); // -1 if (str.indexOf('Hello') !== -1) { // 문자열 str에 'hello'가 포함되어 있는 경우에 처리할 내용 } // ES6: String.prototype.includes if (str.includes('Hello')) { // 문자열 str에 'hello'가 포함되어 있는 경우에 처리할 내용 }
String.prototype.lastIndexOf(searchString, fromIndex) : number
인수로 전달한 문자 또는 문자열을 대상 문자열에서 검색하여 마지막으로 발견된 곳의 index를 반환한다. 발견하지 못한 경우 -1을 반환한다.
2번째 인수(fromIndex)가 전달되면 검색 시작 위치를 fromIndex으로 이동하여 역방향으로 검색을 시작한다. 이때 검색 범위는 0 ~ fromIndex이며 반환값은 indexOf 메소드와 동일하게 발견된 곳의 index이다.
const str = 'Hello World'; console.log(str.lastIndexOf('World')); // 6 console.log(str.lastIndexOf('l')); // 9 console.log(str.lastIndexOf('o', 5)); // 4 console.log(str.lastIndexOf('o', 8)); // 7 console.log(str.lastIndexOf('l', 10)); // 9 console.log(str.lastIndexOf('H', 0)); // 0 console.log(str.lastIndexOf('W', 5)); // -1 console.log(str.lastIndexOf('x', 8)); // -1
🔥 String.prototype.replace(searchValue, replaceValue) : string
첫번째 인수로 전달한 문자열 또는 정규표현식을 대상 문자열에서 검색하여 두번째 인수로 전달한 문자열로 대체한다.
원본 문자열은 변경되지 않고 결과가 반영된 새로운 문자열을 반환한다.
검색된 문자열이 여럿 존재할 경우 첫번째로 검색된 문자열만 대체된다.
searchValue: 문자 or 정규표현식
replaceValue: 문자 or 콜백함수(searchValue를 인자로 받아 리턴값으로 대체)
const str = 'Hello world'; // 첫번째로 검색된 문자열만 대체하여 새로운 문자열을 반환한다. str.replace('world', 'Lee'); // Hello Lee // 특수한 교체 패턴을 사용할 수 있다. ($& => 검색된 문자열) str.replace(‘world’, ‘$&‘); // Hello world /* 정규표현식 g(Global): 문자열 내의 모든 패턴을 검색한다. i(Ignore case): 대소문자를 구별하지 않고 검색한다. */ str.replace(/hello/gi, ‘Lee’); // Lee world
const camelCase = ‘helloWorld’; // 두번째 인수로 치환 함수를 전달할 수 있다. // 특정 문자를 검색해 모두 대문자로 치환 하는 코드 // 문자를 찾아 인수로 match에 대입해 함수 실행 camelCase.replace(“World”, match => match.toUpperCase()); // “helloWORLD” // /.[A-Z]/g => 1문자와 대문자의 조합을 문자열 전체에서 검색한다. camelCase.replace(/.[A-Z]/g, function (match) { // match : oW => match[0] : o, match[1] : W return match[0] + ‘_’ + match[1].toLowerCase(); }); // hello_world // /(.)([A-Z])/g => 1문자와 대문자의 조합 // $1 => (.) // $2 => ([A-Z]) camelCase.replace(/(.)([A-Z])/g, ‘$1_$2’).toLowerCase(); // hello_world
const snakeCase = ‘hello_world’; // /_./g => _와 1문자의 조합을 문자열 전체에서 검색한다. snakeCase.replace(/_./g, function (match) { // match : _w => match[1] : w return match[1].toUpperCase(); }); // helloWorld
특수한 정규식용 교체패턴
$` 문자 대체(replace) 시 일치한 문자 이전 값 참조 $’ 문자 대체(replace) 시 일치한 문자 이후 값 참조 $+ 문자 대체(replace) 시 마지막으로 캡처된 값 참조 $& 문자 대체(replace) 시 일치한 문자 결과 전체 참조 $_ 문자 대체(replace) 시 입력(input)된 문자 전체 참조 $1~9 문자 대체(replace) 시 캡처(Capture)된 값 참조
.replace(‘ ‘,”) // 첫번째 공백 제거 .replace(/\-/g,”) // 특정문자 제거1 (-) .replace(/,/g,”) // 특정문자 제거2(,) .replace(/^\s+/,”) // 앞의 공백 제거 .replace(/\s+$/,”) // 뒤의 공백 제거 .replace(/^\s+|\s+$/g,”) // 앞뒤 공백 제거 .replace(/\s/g,”) // 문자열 내의 모든 공백 제거 .replace(/
/g,”) // n개행 제거 .replace(/\r/g,”) // 엔터 제거
String.prototype.split(separator, limit) : string[]
첫번째 인수로 전달한 문자열 또는 정규표현식을 대상 문자열에서 검색하여 문자열을 구분한 후 분리된 각 문자열로 이루어진 배열 을 반환한다.
원본 문자열은 변경되지 않는다.
인수가 없는 경우, 대상 문자열 전체를 단일 요소로 하는 배열을 반환한다.
const str = ‘How are you doing?’; // 공백으로 구분(단어로 구분)하여 배열로 반환한다 console.log(str.split(‘ ‘)); // [ ‘How’, ‘are’, ‘you’, ‘doing?’ ] // 각 문자를 모두 분리한다 console.log(str.split(”)); // [ ‘H’,’o’,’w’,’ ‘,’a’,’r’,’e’,’ ‘,’y’,’o’,’u’,’ ‘,’d’,’o’,’i’,’n’,’g’,’?’ ] // 정규 표현식 console.log(str.split(/\s/)); // [ ‘How’, ‘are’, ‘you’, ‘doing?’ ] // 인수가 없는 경우, 대상 문자열 전체를 단일 요소로 하는 배열을 반환한다. console.log(str.split()); // [ ‘How are you doing?’ ] // 공백으로 구분하여 배열로 반환한다. 단 요소수는 3개까지만 허용한다 console.log(str.split(‘ ‘, 3)); // [ ‘How’, ‘are’, ‘you’ ] // ‘o’으로 구분하여 배열로 반환한다. console.log(str.split(‘o’)); // [ ‘H’, ‘w are y’, ‘u d’, ‘ing?’ ]
String.prototype.substring(star, end) : string
첫번째 인수로 전달한 start 인덱스에 해당하는 문자부터 두번째 인자에 전달된 end 인덱스에 해당하는 문자의 바로 이전 문자까지를 모두 반환한다.
첫번째 인수 < 두번째 인수의 관계가 성립된다. 첫번째 인수 > 두번째 인수 : 아규먼트 순서를 맞추기 위해 두 인수는 자동 교환된다. 두번째 인수가 생략된 경우 : 해당 문자열의 끝까지 반환한다. 인수 < 0 또는 NaN인 경우 : 0으로 취급된다. 인수 > 문자열의 길이(str.length) : 인수는 문자열의 길이(str.length)으로 취급된다.
const str = ‘Hello World’; // str.length == 11 str.substring(1, 4); // ell // 첫번째 인수 > 두번째 인수 : 순서 맞추기 위해 자동 교환된다. str.substring(4, 1); // ell // 두번째 인수가 생략된 경우 : 해당 문자열의 끝까지 반환한다. str.substring(4); // o World str.substring(4,); // o World // 인수 < 0 또는 NaN인 경우 : 0으로 취급된다. str.substring(-2); // Hello World // 인수 > 문자열의 길이(str.length) : 인수는 문자열의 길이(str.length)으로 취급된다. str.substring(1, 12); // ello World str.substring(11); // ” str[10] == ‘d’ str.substring(20); // ” str.substring(0, str.indexOf(‘ ‘)); // ‘Hello’ str.substring(str.indexOf(‘ ‘) + 1, str.length); // ‘World’
String.prototype.slice(start, end) : string
String.prototype.substring과 동일하다.
단, String.prototype.slice는 음수의 인수를 전달할 수 있다.
const str = ‘hello world’; // 인수 < 0 또는 NaN인 경우 : 0으로 취급된다. str.substring(-5); // 'hello world' // 뒤에서 5자리를 잘라내어 반환한다. str.slice(-5); // 'world' // 2번째부터 마지막 문자까지 잘라내어 반환 tr.substring(2); // llo world str.slice(2); // llo world // 0번째부터 5번째 이전 문자까지 잘라내어 반환 str.substring(0, 5); // hello str.slice(0, 5); // hello
String.prototype.toLowerCase() : string
대상 문자열의 모든 문자를 소문자로 변경한다.
String.prototype.toUpperCase() : string
대상 문자열의 모든 문자를 대문자로 변경한다.
String.prototype.trim() : string
대상 문자열 양쪽 끝에 있는 공백 문자를 제거한 문자열을 반환한다.
const str = ' foo '; console.log(str.trim()); // 'foo' // String.prototype.replace console.log(str.replace(/\s/g, '')); // 'foo' console.log(str.replace(/^\s+/g, '')); // 'foo ' console.log(str.replace(/\s+$/g, '')); // ' foo' // String.prototype.{trimStart,trimEnd} : Proposal stage 3 console.log(str.trimStart()); // 'foo ' console.log(str.trimEnd()); // ' foo'
String.prototype.repeat(count) : string
인수로 전달한 숫자만큼 반복해 연결한 새로운 문자열을 반환한다.
count가 0이면 빈 문자열을 반환하고 음수이면 RangeError를 발생시킨다.
'abc'.repeat(0); // '' 'abc'.repeat(1); // 'abc' 'abc'.repeat(2); // 'abcabc' 'abc'.repeat(2.5); // 'abcabc' (2.5 → 2) 'abc'.repeat(-1); // RangeError: Invalid count value
String.prototype.includes(searchString, position) : boolean
인수로 전달한 문자열이 포함되어 있는지를 검사하고 결과를 불리언 값으로 반환한다.
두번째 인수는 옵션으로 검색할 위치를 나타내는 정수이다.
const str = 'hello world'; str.includes('hello'); // true str.includes('hello', 0); // true str.includes('hello', 2); // false // String.prototype.indexOf 메소드로 대체할 수 있다. str.indexOf('hello'); // 0
String.prototype.padStart(targetLength [, padString])
첫번째 인수로 전체 스트링 길이를 지정하고, 만일 현재 문자열의 길이가 인수보다 짧다면, 그 빈 나머지를 두번째 인수값으로 채운다.
채워넣기는 대상 문자열의 시작(좌측)부터 적용
'abc'.padStart(10); // " abc" 'abc'.padStart(10, "foo"); // "foofoofabc" 'abc'.padStart(6,"123465"); // "123abc" 'abc'.padStart(8, "0"); // "00000abc" 'abc'.padStart(1); // "abc"
padEnd() 는 우측부터 적용
'abc'.padEnd(10); // "abc " 'abc'.padEnd(10, "foo"); // "abcfoofoof" 'abc'.padEnd(6, "123456"); // "abc123" 'abc'.padEnd(1); // "abc"
메소드 설명 String.fromCharCode() 쉼표로 구분되는 일련의 유니코드에 해당하는 문자들로 구성된 문자열을 반환함. String.fromCodePoint() 쉼표로 구분되는 일련의 코드 포인트(code point)에 해당하는 문자들로 구성된 문자열을 반환함. String.raw() 템플릿 문자열(template string)의 원형을 반환함.
프로토타입 메소드 설명 indexOf() String 인스턴스에서 특정 문자나 문자열이 처음으로 등장하는 위치의 인덱스를 반환함. lastIndexOf() String 인스턴스에서 특정 문자나 문자열이 마지막으로 등장하는 위치의 인덱스를 반환함. charAt() String 인스턴스에서 전달받은 인덱스에 위치한 문자를 반환함. charCodeAt() String 인스턴스에서 전달받은 인덱스에 위치한 문자의 UTF-16 코드를 반환함. (0 ~ 65535) charPointAt() String 인스턴스에서 전달받은 인덱스에 위치한 문자의 유니코드 코드 포인트(unicode code point)를 반환함. slice() String 인스턴스에서 전달받은 시작 인덱스부터 종료 인덱스 바로 앞까지의 문자열을 추출한 새 문자열을 반환함. substring() String 인스턴스에서 전달받은 시작 인덱스부터 종료 인덱스 바로 앞까지의 문자열을 추출한 새 문자열을 반환함. substr() String 인스턴스에서 전달받은 시작 인덱스부터 길이만큼의 문자열을 추출한 새로운 문자열을 반환함. split() String 인스턴스에서 구분자(separator)를 기준으로 나눈 후, 나뉜 문자열을 하나의 배열로 반환함. concat() String 인스턴스에 전달받은 문자열을 결합한 새로운 문자열을 반환함. toUpperCase() String 인스턴스의 모든 문자를 대문자로 변환한 새로운 문자열을 반환함. toLowerCase() String 인스턴스의 모든 문자를 소문자로 변환한 새로운 문자열을 반환함. trim() String 인스턴스의 양 끝에 존재하는 공백과 모든 줄 바꿈 문자(LF, CR 등)를 제거한 새로운 문자열을 반환함. search() 인수로 전달받은 정규 표현식에 맞는 문자나 문자열이 처음으로 등장하는 위치의 인덱스를 반환함. replace() 인수로 전달받은 패턴에 맞는 문자열을 대체 문자열로 변환한 새 문자열을 반환함. match() 인수로 전달받은 정규 표현식에 맞는 문자열을 찾아서 하나의 배열로 반환함. includes() 인수로 전달받은 문자나 문자열이 포함되어 있는지를 검사한 후 그 결과를 불리언 값으로 반환함. startsWith() 인수로 전달받은 문자나 문자열로 시작되는지를 검사한 후 그 결과를 불리언 값으로 반환함. endsWith() 인수로 전달받은 문자나 문자열로 끝나는지를 검사한 후 그 결과를 불리언 값으로 반환함. toLocaleUpperCase() 영문자뿐만 아니라 모든 언어의 문자를 대문자로 변환한 새로운 문자열을 반환함. toLocaleLowerCase() 영문자뿐만 아니라 모든 언어의 문자를 소문자로 변환한 새로운 문자열을 반환함. localeCompare() 인수로 전달받은 문자열과 정렬 순서로 비교하여 그 결과를 정수 값으로 반환함. normalize() 해당 문자열의 유니코드 표준화 양식(Unicode Normalization Form)을 반환함. repeat() 해당 문자열을 인수로 전달받은 횟수만큼 반복하여 결합한 새로운 문자열을 반환함. toString() String 인스턴스의 값을 문자열로 반환함. valueOf() String 인스턴스의 값을 문자열로 반환함.
자바스크립트엔 글자 하나만 저장할 수 있는 별도의 자료형이 없습니다. 텍스트 형식의 데이터는 길이에 상관없이 문자열 형태로 저장됩니다.
자바스크립트에서 문자열은 페이지 인코딩 방식과 상관없이 항상 UTF-16 형식을 따릅니다.
따옴표의 종류가 무엇이 있었는지 상기해봅시다.
문자열은 작은따옴표나 큰따옴표, 백틱으로 감쌀 수 있습니다.
let single = ‘작은따옴표’; let double = “큰따옴표”; let backticks = `백틱`;
작은따옴표와 큰따옴표는 기능상 차이가 없습니다. 그런데 백틱엔 특별한 기능이 있습니다. 표현식을 ${…} 로 감싸고 이를 백틱으로 감싼 문자열 중간에 넣어주면 해당 표현식을 문자열 중간에 쉽게 삽입할 수 있죠. 이런 방식을 템플릿 리터럴(template literal)이라고 부릅니다.
function sum(a, b) { return a + b; } alert(`1 + 2 = ${sum(1, 2)}.`); // 1 + 2 = 3.
백틱을 사용하면 문자열을 여러 줄에 걸쳐 작성할 수도 있습니다.
let guestList = `손님: * John * Pete * Mary `; alert(guestList); // 손님 리스트를 여러 줄에 걸쳐 작성함
자연스럽게 여러 줄의 문자열이 만들어졌네요. 작은따옴표나 큰따옴표를 사용하면 위와 같은 방식으로 여러 줄짜리 문자열을 만들 수 없습니다.
아래 예시를 실행해봅시다. 에러가 발생합니다.
let guestList = “손님: // Error: Invalid or unexpected token * John”;
작은따옴표나 큰따옴표로 문자열을 표현하는 방식은 자바스크립트가 만들어졌을 때부터 있었습니다. 이때는 문자열을 여러 줄에 걸쳐 작성할 생각조차 못 했던 시기였죠. 백틱은 그 이후에 등장한 문법이기 때문에 따옴표보다 다양한 기능을 제공합니다.
백틱은 ‘템플릿 함수(template function)’에서도 사용됩니다. func`string` 같이 첫 번째 백틱 바로 앞에 함수 이름( func )을 써주면, 이 함수는 백틱 안의 문자열 조각이나 표현식 평가 결과를 인수로 받아 자동으로 호출됩니다. 이런 기능을 ‘태그드 템플릿(tagged template)’이라 부르는데, 태그드 템플릿을 사용하면 사용자 지정 템플릿에 맞는 문자열을 쉽게 만들 수 있습니다. 태그드 템플릿과 템플릿 함수에 대한 자세한 내용은 MDN 문서에서 확인해보세요. 참고로 이 기능은 자주 사용되진 않습니다.
‘줄 바꿈 문자(newline character)’라 불리는 특수기호
을 사용하면 작은따옴표나 큰따옴표로도 여러 줄 문자열을 만들 수 있습니다.
let guestList = “손님:
* John
* Pete
* Mary”; alert(guestList); // 손님 리스트를 여러 줄에 걸쳐 작성함
따옴표를 이용해 만든 여러 줄 문자열과 백틱을 이용해 만든 여러 줄 문자열은 표현 방식만 다를 뿐 차이가 없습니다.
let str1 = “Hello
World”; // ‘줄 바꿈 기호’를 사용해 두 줄짜리 문자열을 만듦 // 백틱과 일반적인 줄 바꿈 방법(엔터)을 사용해 두 줄짜리 문자열을 만듦 let str2 = `Hello World`; alert(str1 == str2); // true
자바스크립트엔 줄 바꿈 문자를 비롯한 다양한 ‘특수’ 문자들이 있습니다.
특수 문자 목록:
특수 문자 설명
줄 바꿈 \r 캐리지 리턴(carriage return). Windows에선 캐리지 리턴과 줄 바꿈 특수 문자를 조합( \r
)해 줄을 바꿉니다. 캐리지 리턴을 단독으론 사용하는 경우는 없습니다. \’ , \” 따옴표 \\ 역슬래시 \t 탭 \b , \f , \v 각각 백스페이스(Backspace), 폼 피드(Form Feed), 세로 탭(Vertical Tab)을 나타냅니다. 호환성 유지를 위해 남아있는 기호로 요즘엔 사용하지 않습니다. \xXX 16진수 유니코드 XX 로 표현한 유니코드 글자입니다(예시: 알파벳 ‘z’ 는 ‘\x7A’ 와 동일함). \uXXXX UTF-16 인코딩 규칙을 사용하는 16진수 코드 XXXX 로 표현한 유니코드 기호입니다. XXXX 는 반드시 네 개의 16진수로 구성되어야 합니다(예시: \u00A9 는 저작권 기호 © 의 유니코드임). \u{X…XXXXXX} (한 개에서 여섯 개 사이의 16진수 글자) UTF-32로 표현한 유니코드 기호입니다. 몇몇 특수한 글자는 두 개의 유니코드 기호를 사용해 인코딩되므로 4바이트를 차지합니다. 이 방법을 사용하면 긴 코드를 삽입할 수 있습니다.
유니코드를 사용한 예시:
alert( “\u00A9” ); // © alert( “\u{20331}” ); // 佫, 중국어(긴 유니코드) alert( “\u{1F60D}” ); // 😍, 웃는 얼굴 기호(긴 유니코드)
모든 특수 문자는 ‘이스케이프 문자(escape character)’라고도 불리는 역슬래시 (backslash character) \ 로 시작합니다.
역슬래시는 문자열 내에 따옴표를 넣을 때도 사용할 수 있습니다.
예시:
alert( ‘I\’m the Walrus!’ ); // I’m the Walrus!
위 예시에서 살펴본 바와 같이 문자열 내의 따옴표엔 \ 를 꼭 붙여줘야 합니다. 이렇게 하지 않으면 자바스크립트는 해당 따옴표가 문자열을 닫는 용도로 사용된 것이라 해석하기 때문입니다.
이스케이프 문자는 문자열을 감쌀 때 사용한 따옴표와 동일한 따옴표에만 붙여주면 됩니다. 문자열 내에서 좀 더 우아하게 따옴표를 사용하려면 아래와 같이 따옴표 대신 백틱으로 문자열을 감싸주면 됩니다.
alert( `I’m the Walrus!` ); // I’m the Walrus!
역슬래시 \ 는 문자열을 정확하게 읽기 위한 용도로 만들어졌으므로 \ 는 제 역할이 끝나면 사라집니다. 메모리에 저장되는 문자열엔 \ 가 없습니다. 앞선 예시들을 실행했을 때 뜨는 alert 창을 통해 이를 확인할 수 있습니다.
그렇다면 문자열 안에 역슬래시 \ 를 보여줘야 하는 경우엔 어떻게 해야 할까요?
\\ 같이 역슬래시를 두 개 붙이면 됩니다.
length 프로퍼티엔 문자열의 길이가 저장됩니다.
alert( `My
`.length ); // 3
은 ‘특수 문자’ 하나로 취급되기 때문에 My
의 길이는 3 입니다.
length 는 프로퍼티입니다. 자바스크립트 이외의 언어를 사용했던 개발자들은 str.length 가 아닌 str.length() 로 문자열의 길이를 알아내려고 하는 경우가 있습니다. 하지만 원하는 대로 동작하지 않습니다. length 는 함수가 아니고, 숫자가 저장되는 프로퍼티라는 점에 주의하시기 바랍니다. 뒤에 괄호를 붙일 필요가 없습니다.
문자열 내 특정 위치인 pos 에 있는 글자에 접근하려면 [pos] 같이 대괄호를 이용하거나 str.charAt(pos)라는 메서드를 호출하면 됩니다. 위치는 0부터 시작합니다.
let str = `Hello`; // 첫 번째 글자 alert( str[0] ); // H alert( str.charAt(0) ); // H // 마지막 글자 alert( str[str.length – 1] ); // o
근래에는 대괄호를 이용하는 방식을 사용합니다. charAt 은 하위 호환성을 위해 남아있는 메서드라고 생각하시면 됩니다.
두 접근 방식의 차이는 반환할 글자가 없을 때 드러납니다. 접근하려는 위치에 글자가 없는 경우 [] 는 undefined 를, charAt 은 빈 문자열을 반환합니다.
let str = `Hello`; alert( str[1000] ); // undefined alert( str.charAt(1000) ); // ” (빈 문자열)
for..of 를 사용하면 문자열을 구성하는 글자를 대상으로 반복 작업을 할 수 있습니다.
for (let char of “Hello”) { alert(char); // H,e,l,l,o (char는 순차적으로 H, e, l, l, o가 됩니다.) }
문자열은 수정할 수 없습니다. 따라서 문자열의 중간 글자 하나를 바꾸려고 하면 에러가 발생합니다.
직접 실습해봅시다.
let str = ‘Hi’; str[0] = ‘h’; // Error: Cannot assign to read only property ‘0’ of string ‘Hi’ alert( str[0] ); // 동작하지 않습니다.
이런 문제를 피하려면 완전히 새로운 문자열을 하나 만든 다음, 이 문자열을 str 에 할당하면 됩니다.
예시:
let str = ‘Hi’; str = ‘h’ + str[1]; // 문자열 전체를 교체함 alert( str ); // hi
유사한 예시는 이어지는 절에서 살펴보겠습니다.
메서드 toLowerCase()와 toUpperCase()는 대문자를 소문자로, 소문자를 대문자로 변경(케이스 변경)시켜줍니다.
alert( ‘Interface’.toUpperCase() ); // INTERFACE alert( ‘Interface’.toLowerCase() ); // interface
글자 하나의 케이스만 변경하는 것도 가능합니다.
alert( ‘Interface'[0].toLowerCase() ); // ‘i’
문자열에서 부분 문자열(substring)을 찾는 방법은 여러 가지가 있습니다.
첫 번째 방법은 str.indexOf(substr, pos) 메서드를 이용하는 것입니다.
이 메서드는 문자열 str 의 pos 에서부터 시작해, 부분 문자열 substr 이 어디에 위치하는지를 찾아줍니다. 원하는 부분 문자열을 찾으면 위치를 반환하고 그렇지 않으면 -1 을 반환합니다.
예시:
let str = ‘Widget with id’; alert( str.indexOf(‘Widget’) ); // 0, str은 ‘Widget’으로 시작함 alert( str.indexOf(‘widget’) ); // -1, indexOf는 대·소문자를 따지므로 원하는 문자열을 찾지 못함 alert( str.indexOf(“id”) ); // 1, “id”는 첫 번째 위치에서 발견됨 (Widget에서 id)
str.indexOf(substr, pos) 의 두 번째 매개변수 pos 는 선택적으로 사용할 수 있는데, 이를 명시하면 검색이 해당 위치부터 시작됩니다.
부분 문자열 “id” 는 위치 1 에서 처음 등장하는데, 두 번째 인수에 2 를 넘겨 “id” 가 두 번째로 등장하는 위치가 어디인지 알아봅시다.
let str = ‘Widget with id’; alert( str.indexOf(‘id’, 2) ) // 12
문자열 내 부분 문자열 전체를 대상으로 무언가를 하고 싶다면 반복문 안에 indexOf 를 사용하면 됩니다. 반복문이 하나씩 돌 때마다 검색 시작 위치가 갱신되면서 indexOf 가 새롭게 호출됩니다.
let str = ‘As sly as a fox, as strong as an ox’; let target = ‘as’; // as를 찾아봅시다. let pos = 0; while (true) { let foundPos = str.indexOf(target, pos); if (foundPos == -1) break; alert( `위치: ${foundPos}` ); pos = foundPos + 1; // 다음 위치를 기준으로 검색을 이어갑니다. }
동일한 알고리즘을 사용해 코드만 짧게 줄이면 다음과 같습니다.
let str = “As sly as a fox, as strong as an ox”; let target = “as”; let pos = -1; while ((pos = str.indexOf(target, pos + 1)) != -1) { alert( `위치: ${pos}` ); }
str.lastIndexOf(substr, position) str.lastIndexOf(substr, position)는 indexOf 와 유사한 기능을 하는 메서드입니다. 문자열 끝에서부터 부분 문자열을 찾는다는 점만 다릅니다. 반환되는 부분 문자열 위치는 문자열 끝이 기준입니다.
if 문의 조건식에 indexOf 를 쓸 때 주의할 점이 하나 있습니다. 아래와 같이 코드를 작성하면 원하는 결과를 얻을 수 없습니다.
let str = “Widget with id”; if (str.indexOf(“Widget”)) { alert(“찾았다!”); // 의도한 대로 동작하지 않습니다. }
str.indexOf(“Widget”) 은 0 을 반환하는데, if 문에선 0 을 false 로 간주하므로 alert 창이 뜨지 않습니다.
따라서 부분 문자열 여부를 검사하려면 아래와 같이 -1 과 비교해야 합니다.
let str = “Widget with id”; if (str.indexOf(“Widget”) != -1) { alert(“찾았다!”); // 의도한 대로 동작합니다. }
오래전부터 전해 오는 비트(bitwise) NOT 연산자 ~ 를 사용한 기법 하나를 소개해드리겠습니다. 비트 NOT 연산자는 피연산자를 32비트 정수로 바꾼 후(소수부는 모두 버려짐) 모든 비트를 반전합니다.
따라서 n 이 32비트 정수일 때 ~n 은 -(n+1) 이 됩니다.
예시:
alert( ~2 ); // -3, -(2+1)과 같음 alert( ~1 ); // -2, -(1+1)과 같음 alert( ~0 ); // -1, -(0+1)과 같음 alert( ~-1 ); // 0, -(-1+1)과 같음
위 예시에서 본 바와 같이 부호가 있는 32비트 정수 n 중, ~n 을 0 으로 만드는 경우는 n == -1 일 때가 유일합니다.
이를 응용해서 indexOf 가 -1 을 반환하지 않는 경우를 if ( ~str.indexOf(“…”) ) 로 검사해 봅시다.
이렇게 ~str.indexOf(“…”) 를 사용하면 코드의 길이를 줄일 수 있습니다.
let str = “Widget”; if (~str.indexOf(“Widget”)) { alert( ‘찾았다!’ ); // 의도한 대로 동작합니다. }
사실 이렇게 언어 특유의 기능을 사용해 직관적이지 않은 코드를 작성하는 것을 추천해 드리진 않습니다. 그렇지만 위와 같은 기법은 오래된 스크립트에서 쉽게 만날 수 있기 때문에 알아두어야 합니다.
if (~str.indexOf(…)) 패턴의 코드를 만나면 ‘부분 문자열인지 확인’하는 코드라고 기억해둡시다.
참고로 -1 이외에도 ~ 연산자 적용 시 0 을 반환하는 숫자는 다양합니다. 아주 큰 숫자에 ~ 연산자를 적용하면 32비트 정수로 바꾸는 과정에서 잘림 현상이 발생하기 때문이죠. 이런 숫자 중 가장 큰 숫자는 4294967295 입니다( ~4294967295 는 0 임). 문자열이 아주 길지 않은 경우에만 ~ 연산자가 의도한 대로 작동한다는 점을 알고 계시길 바랍니다.
모던 자바스크립트에선 .includes 메서드(아래에서 배움)를 사용해 부분 문자열 포함 여부를 검사합니다. 이런 기법은 오래된 자바스크립트에서만 볼 수 있습니다.
비교적 근래에 나온 메서드인 str.includes(substr, pos)는 str 에 부분 문자열 substr 이 있는지에 따라 true 나 false 를 반환합니다.
부분 문자열의 위치 정보는 필요하지 않고 포함 여부만 알고 싶을 때 적합한 메서드입니다.
alert( “Widget with id”.includes(“Widget”) ); // true alert( “Hello”.includes(“Bye”) ); // false
str.includes 에도 str.indexOf 처럼 두 번째 인수를 넘기면 해당 위치부터 부분 문자열을 검색합니다.
alert( “Widget”.includes(“id”) ); // true alert( “Widget”.includes(“id”, 3) ); // false, 세 번째 위치 이후엔 “id”가 없습니다.
메서드 str.startsWith와 str.endsWith는 메서드 이름 그대로 문자열 str 이 특정 문자열로 시작하는지(start with) 여부와 특정 문자열로 끝나는지(end with) 여부를 확인할 때 사용할 수 있습니다.
자바스크립트엔 부분 문자열 추출과 관련된 메서드가 세 가지 있습니다. 세 가지 메서드 substring , substr , slice 를 하나씩 알아봅시다.
str.slice(start [, end]) 문자열의 start 부터 end 까지( end 는 미포함)를 반환합니다. 예시: let str = “stringify”; alert( str.slice(0, 5) ); // ‘strin’, 0번째부터 5번째 위치까지(5번째 위치의 글자는 포함하지 않음) alert( str.slice(0, 1) ); // ‘s’, 0번째부터 1번째 위치까지(1번째 위치의 자는 포함하지 않음) 두 번째 인수가 생략된 경우엔, 명시한 위치부터 문자열 끝까지를 반환합니다. let str = “stringify”; alert( str.slice(2) ); // ringify, 2번째부터 끝까지 start 와 end 는 음수가 될 수도 있습니다. 음수를 넘기면 문자열 끝에서부터 카운팅을 시작합니다. let str = “stringify”; // 끝에서 4번째부터 시작해 끝에서 1번째 위치까지 alert( str.slice(-4, -1) ); // gif str.substring(start [, end]) start 와 end 사이에 있는 문자열을 반환합니다. substring 은 slice 와 아주 유사하지만 start 가 end 보다 커도 괜찮다는 데 차이가 있습니다. 예시: let str = “stringify”; // 동일한 부분 문자열을 반환합니다. alert( str.substring(2, 6) ); // “ring” alert( str.substring(6, 2) ); // “ring” // slice를 사용하면 결과가 다릅니다. alert( str.slice(2, 6) ); // “ring” (같음) alert( str.slice(6, 2) ); // “” (빈 문자열) substring 은 음수 인수를 허용하지 않습니다. 음수는 0 으로 처리됩니다. str.substr(start [, length]) start 에서부터 시작해 length 개의 글자를 반환합니다. substr 은 끝 위치 대신에 길이를 기준으로 문자열을 추출한다는 점에서 substring 과 slice 와 차이가 있습니다. let str = “stringify”; alert( str.substr(2, 4) ); // ring, 두 번째부터 글자 네 개 첫 번째 인수가 음수면 뒤에서부터 개수를 셉니다. let str = “stringify”; alert( str.substr(-4, 2) ); // gi, 끝에서 네 번째 위치부터 글자 두 개
부분 문자열 추출과 관련된 메서드를 요약해 봅시다.
메서드 추출할 부분 문자열 음수 허용 여부(인수) slice(start, end) start 부터 end 까지( end 는 미포함) 음수 허용 substring(start, end) start 와 end 사이 음수는 0 으로 취급함 substr(start, length) start 부터 length 개의 글자 음수 허용
어떤 메서드를 선택해야 하나요? 모두 사용해도 괜찮습니다. 그런데 substr 에는 단점이 하나 있습니다. substr 는 코어 자바스크립트 명세서(ECMA-262 – 옮긴이)가 아닌, 구식 스크립트에 대응하기 위해 남겨 둔 브라우저 전용 기능들을 명시해 놓은 부록 B(Annex B)에 정의되어있습니다. 거의 모든 곳에서 이 메서드가 동작하긴 하지만 브라우저 이외의 호스트 환경에서는 제대로 동작하지 않을 수 있습니다. 남은 두 메서드 중 slice 는 음수 인수를 허용한다는 측면에서 substring 보다 좀 더 유연합니다. 메서드 이름도 더 짧죠. 따라서 세 메서드 중 slice 만 외워놓고 사용해도 충분할 것 같습니다.
비교 연산자 챕터에서 알아보았듯이 문자열을 비교할 땐 알파벳 순서를 기준으로 글자끼리 비교가 이뤄집니다.
그런데 아래와 같이 몇 가지 이상해 보이는 것들이 있습니다.
소문자는 대문자보다 항상 큽니다. alert( ‘a’ > ‘Z’ ); // true 발음 구별 기호(diacritical mark)가 붙은 문자는 알파벳 순서 기준을 따르지 않습니다. alert( ‘Österreich’ > ‘Zealand’ ); // true (Österreich는 오스트리아를 독일어로 표기한 것임 – 옮긴이) 이런 예외사항 때문에 이름순으로 국가를 나열할 때 예상치 못한 결과가 나올 수 있습니다. 사람들은 Österreich 가 Zealand 보다 앞서 나올 것이라 예상하는데 그렇지 않죠.
자바스크립트 내부에서 문자열이 어떻게 표시되는지 상기하며 원인을 알아봅시다.
모든 문자열은 UTF-16을 사용해 인코딩되는데, UTF-16에선 모든 글자가 숫자 형식의 코드와 매칭됩니다. 코드로 글자를 얻거나 글자에서 연관 코드를 알아낼 수 있는 메서드는 다음과 같습니다.
str.codePointAt(pos) pos 에 위치한 글자의 코드를 반환합니다. // 글자는 같지만 케이스는 다르므로 반환되는 코드가 다릅니다. alert( “z”.codePointAt(0) ); // 122 alert( “Z”.codePointAt(0) ); // 90 String.fromCodePoint(code) 숫자 형식의 code 에 대응하는 글자를 만들어줍니다. alert( String.fromCodePoint(90) ); // Z \u 뒤에 특정 글자에 대응하는 16진수 코드를 붙이는 방식으로도 원하는 글자를 만들 수 있습니다. // 90을 16진수로 변환하면 5a입니다. alert( ‘\u005a’ ); // Z
이제 이 배경지식을 가지고 코드 65 와 220 사이(라틴계열 알파벳과 기타 글자들이 여기에 포함됨)에 대응하는 글자들을 출력해봅시다.
let str = ”; for (let i = 65; i <= 220; i++) { str += String.fromCodePoint(i); } alert( str ); // ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ // ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ
보이시나요? 대문자 알파벳이 가장 먼저 나오고 특수 문자 몇 개가 나온 다음에 소문자 알파벳이 나오네요. Ö 은 거의 마지막에 출력됩니다.
이제 왜 a > Z 인지 아시겠죠?
글자는 글자에 대응하는 숫자 형식의 코드를 기준으로 비교됩니다. 코드가 크면 대응하는 글자 역시 크다고 취급되죠. 따라서 a (코드:97)는 Z (코드:90) 보다 크다는 결론이 도출됩니다.
알파벳 소문자의 코드는 대문자의 코드보다 크므로 소문자는 대문자 뒤에 옵니다.
Ö 같은 글자는 일반 알파벳과 멀리 떨어져 있습니다. Ö 의 코드는 알파벳 소문자의 코드보다 훨씬 큽니다.
언어마다 문자 체계가 다르기 때문에 문자열을 ‘제대로’ 비교하는 알고리즘을 만드는 건 생각보다 간단하지 않습니다.
문자열을 비교하려면 일단 페이지에서 어떤 언어를 사용하고 있는지 브라우저가 알아야 합니다.
다행히도 모던 브라우저 대부분이 국제화 관련 표준인 ECMA-402를 지원합니다(IE10은 아쉽게도 Intl.js 라이브러리를 사용해야 합니다).
ECMA-402엔 언어가 다를 때 적용할 수 있는 문자열 비교 규칙과 이를 준수하는 메서드가 정의되어있습니다.
str.localeCompare(str2)를 호출하면 ECMA-402에서 정의한 규칙에 따라 str 이 str2 보다 작은지, 같은지, 큰지를 나타내주는 정수가 반환됩니다.
str 이 str2 보다 작으면 음수를 반환합니다.
이 보다 작으면 음수를 반환합니다. str 이 str2 보다 크면 양수를 반환합니다.
이 보다 크면 양수를 반환합니다. str 과 str2 이 같으면 0 을 반환합니다.
예시:
localeCompare 엔 선택 인수 두 개를 더 전달할 수 있습니다. 기준이 되는 언어를 지정(아무것도 지정하지 않았으면 호스트 환경의 언어가 기준 언어가 됨)해주는 인수와 대·소문자를 구분할지나 “a” 와 “á” 를 다르게 취급할지에 대한 것을 설정해주는 인수가 더 있죠. 자세한 사항은 관련 페이지에서 확인해 보시기 바랍니다.
심화 학습 이번 절에선 문자열을 더 깊게 다룹니다. 이모티콘이나 일부 수학 기호, 상형 문자를 비롯한 희귀 기호 등을 다뤄야 한다면 앞으로 배울 내용이 유용하게 사용될 것입니다. 이런 글자들을 사용할 계획이 없다면 본 절을 넘어가셔도 좋습니다.
자주 사용되는 글자들은 모두 2바이트 코드를 가지고 있습니다. 유럽권 언어에서 사용되는 글자, 숫자, 상형 문자 대다수는 2바이트 표현 체계를 사용합니다.
그런데 2바이트는 65,536(2의 16승 – 옮긴이)개의 조합밖에 만들어내지 못하기 때문에 현존하는 기호를 모두 표현하기에 충분하지 않습니다. 이를 극복하기 위해 사용 빈도가 낮은 기호는 ‘서로게이트 쌍(surrogate pair)’이라 불리는 2바이트 글자들의 쌍을 사용해 인코딩합니다.
서로게이트 쌍을 사용해 인코딩한 기호의 길이는 2 입니다.
alert( ‘𝒳’.length ); // 2, 수학에서 쓰이는 대문자 X(그리스 문자 카이 – 옮긴이) alert( ‘😂’.length ); // 2, 웃으면서 눈물 흘리는 얼굴을 나타내는 이모티콘 alert( ‘𩷶’.length ); // 2, 사용 빈도가 낮은 중국어(상형문자)
자바스크립트가 만들어졌을 당시엔 서로게이트 쌍은 존재하지 않았습니다. 따라서 자바스크립트는 서로게이트 쌍으로 표현한 기호를 제대로 처리하지 못합니다.
위 예시에서 기호는 하나지만 길이는 2 인 것을 보고 의아해하실 수 있는데, 이런 이유 때문이죠.
String.fromCodePoint 와 str.codePointAt 은 명세서에 추가된 지 얼마 안 된 메서드로, 서로게이트 쌍을 제대로 처리할 수 있는 몇 안 되는 메서드 입니다. 두 메서드가 등장하기 전에는 String.fromCharCode와 str.charCodeAt을 사용했었는데, 이 메서드들은 fromCodePoint , codePointAt 과 동일하게 동작하지만 서로게이트 쌍은 처리하지 못합니다.
서로게이트 쌍은 두 글자로 취급되기 때문에 기호를 가져오는 게 꽤 까다롭습니다.
alert( ‘𝒳'[0] ); // 이상한 기호가 출력됨 alert( ‘𝒳'[1] ); // 서로게이트 쌍의 일부가 출력됨
서로게이트 쌍을 구성하는 글자들은 붙어있을 때만 의미가 있다는 점에 유의해야 합니다. 따라서 위 예시를 실행하면 얼럿창엔 의미 없는 쓰레기 기호가 출력됩니다.
기술적으로 서로게이트 쌍은 서로게이트 쌍에 대응하는 코드를 사용해 감지할 수 있습니다. 글자의 코드가 0xd800..0xdbff 사이에 있으면 이 코드는 서로게이트 쌍을 구성하는 첫 번째 글자를 나타낸다는 것을 알 수 있죠. 이 경우 서로게이트 쌍을 구성하는 두 번째 글자의 코드는 반드시 0xdc00..0xdfff 사이에 있어야 합니다. 범위 0xd800..0xdbff 와 0xdc00..0xdfff 는 표준에서 서로게이트 쌍을 위해 일부러 비워둔 코드입니다.
예시를 살펴봅시다.
// charCodeAt는 서로게이트 쌍을 처리하지 못하기 때문에 서로게이트 쌍을 구성하는 부분에 대한 코드를 반환합니다. alert( ‘𝒳’.charCodeAt(0).toString(16) ); // d835, 0xd800과 0xdbff 사이의 코드 alert( ‘𝒳’.charCodeAt(1).toString(16) ); // dcb3, 0xdc00과 0xdfff 사이의 코드
서로게이트 쌍을 다루는 다양한 방법에 대해선 iterable 객체 챕터에서 살펴보겠습니다. 서로게이트 쌍 관련 라이브러리도 있긴 한데 소개해 드릴 만한 라이브러리는 아직까진 없는 상황입니다.
여러 언어에서 베이스가 되는 글자 위나 아래에 발음 구별 기호라 불리는 기호를 붙여 글자를 만듭니다.
a 를 베이스 글자로, àáâäãåā 를 만드는 것 같이 말이죠. 이런 ‘합성’ 글자 대부분은 UTF-16 테이블에서 독자적인 코드를 갖습니다. 그런데 모든 합성 글자에 코드가 부여되지는 않습니다. 조합 가능한 글자의 수가 너무 많기 때문입니다.
임의의 조합을 지원하기 위해 UTF-16에선 몇 개의 유니코드 문자를 남겨두었습니다. 베이스 글자 뒤에 하나 혹은 여러 개의 유니코드 문자를 붙여 베이스 글자를 꾸밀 수 있도록 말이죠.
이를 이용하면 베이스 글자 S 뒤에 ‘윗 점’을 나타내는 유니코드 문자( \u0307 )를 붙여 Ṡ를 만들 수 있습니다.
발음 구별 기호를 하나 붙인 상태에서 추가 발음 구별 기호가 필요한 경우에도 문제가 없습니다. 필요한 기호의 유니코드 문자를 붙여주기만 하면 됩니다.
Ṡ에 ‘아래 점’을 나타내는 유니코드 문자( \u0323 )를 추가해서 ‘S 위와 아래에 점이 붙게’ 해봅시다.
예시:
이런 방식은 엄청난 유연성을 제공하는데, 단점도 있습니다. 눈으로 봤을 때는 같은 글자인데 유니코드 조합이 다른 경우가 생깁니다.
예시:
let s1 = ‘S\u0307\u0323’; // Ṩ, S + 윗 점 + 아랫 점 let s2 = ‘S\u0323\u0307’; // Ṩ, S + 아랫 점 + 윗 점 alert( `s1: ${s1}, s2: ${s2}` ); alert( s1 == s2 ); // 눈으로 보기엔 같은 글자이지만 동등 비교 시 false가 반환됩니다.
이런 문제를 해결하려면 ‘유니코드 정규화(unicode normalization)’라 불리는 알고리즘을 사용해 각 문자열을 동일한 형태로 ‘정규화’해야 합니다.
유니코드 정규화 알고리즘은 str.normalize()에 구현되어 있습니다.
alert( “S\u0307\u0323”.normalize() == “S\u0323\u0307”.normalize() ); // true
S 위, 아래에 점을 붙이는 사례에선 normalize() 를 사용하면 세 개의 글자가 하나로 합쳐집니다. Ṩ 를 나타내는 유니코드 \u1e68 로 말이죠.
alert( “S\u0307\u0323”.normalize().length ); // 1 alert( “S\u0307\u0323”.normalize() == “\u1e68” ); // true
그런데 현실은 항상 이렇지 않습니다. Ṩ 가 하나의 유니코드로 합쳐지는 것은 UTF-16을 만드는 데 참여한 사람들이 Ṩ 는 ‘충분히 나타날 수 있는 사례’라 생각하고, Ṩ 를 UTF-16 테이블에 포함하고 코드를 부여해놓았기 때문입니다.
실무에선 이 절에서 다룬 내용만으로도 충분하지만, 정규화 규칙과 변형에 대해 더 알고 싶다면 유니코드 표준 부록의 Unicode Normalization Forms에 해당 내용이 있으니 참고하시기 바랍니다.
자바스크립트엔 세 종류의 따옴표가 있는데, 이 중 하나인 백틱은 문자열을 여러 줄에 걸쳐 쓸 수 있게 해주고 문자열 중간에 ${…} 을 사용해 표현식도 넣을 수 있다는 점이 특징입니다.
을 사용해 표현식도 넣을 수 있다는 점이 특징입니다. 자바스크립트에선 UTF-16을 사용해 문자열을 인코딩합니다.
같은 특수 문자를 사용할 수 있습니다. \u… 를 사용하면 해당 문자의 유니코드를 사용해 글자를 만들 수 있습니다.
같은 특수 문자를 사용할 수 있습니다. 를 사용하면 해당 문자의 유니코드를 사용해 글자를 만들 수 있습니다. 문자열 내의 글자 하나를 얻으려면 대괄호 [] 를 사용하세요.
를 사용하세요. 부분 문자열을 얻으려면 slice 나 substring 을 사용하세요.
나 을 사용하세요. 소문자로 바꾸려면 toLowerCase , 대문자로 바꾸려면 toUpperCase 를 사용하세요.
, 대문자로 바꾸려면 를 사용하세요. indexOf 를 사용하면 부분 문자열의 위치를 얻을 수 있습니다. 부분 문자열 여부만 알고 싶다면 includes/startsWith/endsWith 를 사용하면 됩니다.
를 사용하면 부분 문자열의 위치를 얻을 수 있습니다. 부분 문자열 여부만 알고 싶다면 를 사용하면 됩니다. 특정 언어에 적합한 비교 기준 사용해 문자열을 비교하려면 localeCompare 를 사용하세요. 이 메서드를 사용하지 않으면 글자 코드를 기준으로 문자열이 비교됩니다.
이외에도 문자열에 쓸 수 있는 유용한 메서드 몇 가지가 있습니다.
str.trim() – 문자열 앞과 끝의 공백 문자를 다듬어 줍니다(제거함).
– 문자열 앞과 끝의 공백 문자를 다듬어 줍니다(제거함). str.repeat(n) – 문자열을 n 번 반복합니다.
– 문자열을 번 반복합니다. 이 외의 메서드는 MDN 문서에서 확인해보시기 바랍니다.
정규 표현식을 사용해 문자열을 찾거나 교체해주는 메서드도 여러 개 있는데 이는 아주 큰 주제이기 때문에 별도의 섹션 정규 표현식에서 다루겠습니다.