본문 바로가기
자바 스크립트

자바스크립트 문자열

by y00ns00 2020. 12. 12.

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

 

따옴표

따옴표의 종류가 무엇이 있었는지 상기해보자

문자열은 작은 따옴표나 큰따옴표,백틱으로 감쌀 수 있다.

let single = '작은따옴표';
let double = "큰따옴표";

let backticks = `백틱`;

작은따옴표와 큰 따옴표는 기능상 차이가 없다. 

하지만 백틱엔 특별한 기능이 있다. 표현식을 ${...}으로 감싸고 이를 백틱으로 감싼 문자열 중간에 넣으면 문자열 중간에 쉽게 삽입할 수 있다. -> 이러한 방식을 템플릿 리터럴 이라고 부른다.

 

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";

작은 따옴표나 큰따옴표로 문자열 표현하는 방식은 자바 스크립트가 만들어졌을 때부터 있었다

백틱은 그 이후에 등장한 분법이기 때문에 따옴표보다 다양한 기능을 제공한다.

 

백틱은 템플릿 함수 에서도 사용된다. func'string'같이 첫 번째 백틱 바로 앞에 함수 이름(func)을 써주면 이 함수는 백틱 안의 문자열 조각이나 표현식 평가 결과를 인수로 받아 자동으로 호출된다. -> 이런 기능을 태그드 템플릿 이라고 부른다.

태그드 템플릿을 사용하면 사용자 지정 템플릿에 맞는 문자열을 쉽게 만들 수 있다.

 

 

 

특수 기호

'줄 바꿈 문자라 불리는 특수기호 \n을 사용하면 작은따옴표나 큰따옴표로도 여러 줄 문자열을 만들 수 있다.

let guestList = "손님:\n * John\n * Pete\n * Mary";

alert(guestList); // 손님 리스트를 여러 줄에 걸쳐 작성함

 

따옴표를 이용해 만든 여러줄 물자열과 백틱을 이용해 만든 여러 줄 문자열은 표현 방식만 다를 뿐 차이가 없다.

let str1 = "Hello\nWorld"; // '줄 바꿈 기호'를 사용해 두 줄짜리 문자열을 만듦

// 백틱과 일반적인 줄 바꿈 방법(엔터)을 사용해 두 줄짜리 문자열을 만듦
let str2 = `Hello
World`;

alert(str1 == str2); // true

자바스크립트에는 줄 바꿈 문자를 비롯한 다양한 `특수` 문자들이 있다.

유니코드 예시 :

alert( "\u00A9" ); // ©
alert( "\u{20331}" ); // 佫, 중국어(긴 유니코드)
alert( "\u{1F60D}" ); // 😍, 웃는 얼굴 기호(긴 유니코드)

모든 특수 문자는 이스케이프 문자(escape character)라고도 불리는 역슬래시 \ 로 시작한다.

 

역슬래시는 문자열 내에 따옴표를 넣을때도 사용할 수 있다.

alert( 'I\'m the Walrus!' ); // I'm the Walrus!

 

 

 

문자열의 길이

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

alert( `My\n`.length ); // 3
// \n은 ‘특수 문자’ 하나로 취급되기 때문에 My\n의 길이는 3이다.

 

특정 글자에 접근하기

문자열 내 특정위치(pos)에 접근하려면 [pos]같이 대괄호를 이용하거나 str.chrAt(pos)라는 메서드를 호출하면 된다. 

let str = `Hello`;

// 첫 번째 글자
alert( str[0] ); // H
alert( str.charAt(0) ); // H

// 마지막 글자
alert( str[str.length - 1] ); // o

근래에는 대괄호를 이용하는 방식을 사용한다.(charAt은 하위 호환성을 위해 남아있는 메서드라고 생각)

 

두 접근 방식의 차이는 반환할 글자가 없을 때 []는 undefined를 charAt은 빈 문자열을 반환한다.

 

 

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] ); // 동작하지 않습니다.

 

 

대,소문자 변경하기

toLowerCase() - 대문자를 소문자로 변경

toUpperCase() - 소문자를 대문자로 변경

 

글자 하나의 케이스만 변경하는 것도 가능하다.

alert( 'Interface'[0].toLowerCase() ); // 'i'

 

 

부분 문자열 찾기

 

str.indexOf

- 문자열 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는 선택적으로 사용할 수 있는데 이를 명시하면 검색이 해당 위치부터 시작

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)

문자열 끝에서부터 부분 문자열을 찾는다는 점이 다르다.

반환되는 부분 문자열 위치는 문자열 끝이 기준

 

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("찾았다!"); // 의도한 대로 동작합니다.
}

 

 

비트 NOT 연산자를 사용한 기법

 

비트 NOT연산자는 피연산자를 32비트 정수로 바꾼 후(소수부는 모두 버림) 모든 비트를 반전한다.

따라서 n이 32비트 정수일 때 ~n은 -(n+1)이 된다.

 

let str = "Widget";

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

if (~str.indexOf(...)) 패턴의 코드를 만나면 '부분 문자열인지 확인’하는 코드라고 생각하면 된다.

 

 

 

includes, startsWith,endsWith

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) 여부를 확인할 때 사용할수 있다.

alert( "Widget".startsWith("Wid") ); // true, "Widget"은 "Wid"로 시작합니다.
alert( "Widget".endsWith("get") ); // true, "Widget"은 "get"으로 끝납니다.

 

 

 

부분 문자열 추출하기

세가지 메서드를 사용  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, 끝에서 네 번째 위치부터 글자 두 개

 

 

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

slice는 음수 인수를 허용한다는 측면에서 substring보다 조금 더 유연하다 

 

 

 

# 문자열에 쓸 수 있는 유용한 메서드

 

str.trim() – 문자열 앞과 끝의 공백 문자를 제거한다.

str.repeat(n) – 문자열을 n번 반복합니다.

 

 

 

문자열 비교하기

문자열을 비교할 땐 알파벳 순서를 기준으로 글자끼리 비교가 이루어 진다.

하지만 몇가지 이상한 것들이 있다.

 

1. 소문자는 대문자보다 항상 크다.

alert( 'a' > 'Z' ); // true

2. 발음 구별 기호가 붙은 문자는 알파벳 순서 기준을 따르지 않는다.

alert( 'Österreich' > 'Zealand' ); // true 

모든 문자열은 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

 

 

문자열 제대로 비교하기

언어마다 문자 체계가 다르기 때문에 문자열을 비교하려면 페이지에서 어떤 언어를 사용하고 있는지 브라우저가 알아야한다.

모던 브라우저 대부분이 국제화 관련 표준 ECMA-402를 지원 (IE10은 Intl.js라이브러리 사용)

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

str.localeCompare(str2)를 호출하면 ECMA-402에서 정의한 규칙에 따라 str이 str2보다 작은지,같은지,큰지를 나타내주는 정수가 반환단다.

str 이 str2보다 작으면 음수를 반환

str 이 str2보다 크면 양수를 반환

str 이 str2과 같으면 0을 반환

 

 

 

출처 : ko.javascript.info/string#

'자바 스크립트' 카테고리의 다른 글

자바스크립트 iterable  (0) 2020.12.14
자바스크립트 배열  (0) 2020.12.13
자바스크립트 숫자형  (0) 2020.12.11
자바스크립트 원시값의 메서드  (1) 2020.12.08
자바 스크립트 심볼형  (0) 2020.12.08

댓글