high performance javascript - chapter 5. strings and regular expressions

103
5 문자열과 정규 표현식 High Performance JavaScript

Upload: hyun-chul-jeon

Post on 29-Nov-2014

809 views

Category:

Documents


3 download

DESCRIPTION

High Performance JavaScript - Chapter 5. Strings and Regular Expressions 하이 퍼포먼스 자바스크립트 - 5장 문자열과 정규 표현식 분량의 한국어 정리 자료 입니다.

TRANSCRIPT

Page 1: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

5문자열과 정규 표현식High Performance JavaScript

Page 2: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

시작하면서..

• 모든 브라우저에서 동작하면서 빠르게 문자열을 조작

• 역추적을 줄여 정규 표현식 성능을 올리는 방법

• 기타 문자열과 정규 표현식을 효율적으로 쓰는 방법

• Steven Levithan : http://blog.stevenlevithan.com/

Page 3: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

1 문자열 병합

• 매우 성능에 민감할 수 있다.

• 루프 + 문자열 병합

Page 4: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

문자열 병합 방법 방법 예제

+ 연산자 str = “a” + “b” + “c”;

+= 연산자 str = “a”; str += “b”;

array.join() str = [“a”, “b”, “c”].join(“”);

string.concat() str = “a”; str = str.concat(“b”, “c”);

Page 5: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

+ 연산자 & += 연산자

• 가장 간편한 방법

• 모던 브라우저는 충분히 최적화 (IE > 7)

Page 6: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

+ 연산자 & += 연산자

1. 메모리에 임시 문자열이 만들어집니다.

2. 병합된 문자열 “onetwo"를 임시 문자열에 할당합니다.

3. 임시 문자열과 str 변수의 현재 값을 합칩니다.

4. 결과를 str에 저장합니다.

str += “one” + “two”;

Page 7: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

+ 연산자 & += 연산자

• 임시 문자열 부분을 제거

• 대부분 브라우저에서 10~40% 향상

str += “one”;str += “two”;

Page 8: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

+ 연산자 & += 연산자

str = str + “one” + “two”;

// str = ((str + “one”) + “two”)와 같습니다.

Page 9: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

+ 연산자 & += 연산자

Page 10: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

+ 연산자 & += 연산자

• 앞의 테크닉은 IE에서 적용되지 않음

• IE8 경우

• 병합할 때 각 부분 문자열의 참조만 저장

• 합쳐진 문자열이 실제로 쓰일때 “진짜” 문자열에 복사되어 사용

• toString(), length, DOM 추가

Page 11: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

+ 연산자 & += 연산자

• IE7 이하

• 매번 문자열을 메모리 새 위치에 복사

largeStr = largeStr + s1 + s2;largeStr += s1 + s2; // 빠름

Page 12: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

파이어폭스와 컴파일 타임 폴딩

function foldingDemo() { var str = "compile" + "-time" + " folding"; str += "this" + " works" + " too"; str = str + "but" + "not" + "this";}alert(foldingDemo.toString());

/* 파이어폭스에서는 이렇게 동작합니다.function foldingDemo() { var str = "compile-time folding"; str += "this works too"; str = str + "but" + "not" + "this";} */

Page 13: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

배열 병합

• Array.prototype.join

• IE7 이하에서만 효과적

Page 14: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

배열 병합var str = "I'm a thirty-five character string.", newStr = "", appends = 5000;

while(appends--) { newStr += str;}

Page 15: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

배열 병합var str = "I'm a thirty-five character string.", strs = [], newStr, appends = 5000;

while(appends--) { strs[strs.length] = str;}newStr = strs.join("");

Page 16: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

String.prototype.concat

// 문자열 하나를 연결합니다.str = str.concat(s1);

// 문자열 세 개를 연결합니다.str = str.concat(s1, s2, s3);

// 매개변수 목록으로 배열을 넘기먼 배열에 포함된 문자열 전체를 연결합니다.str = String.prototype.concat.apply(str, array);

Page 17: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

String.prototype.concat

• 대부분 브라우저에서 느린편

• 배열 매개변수 사용 ≠ 배열 병합

• IE7 이하 엄청난 성능 저하

Page 18: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

2 정규 표현식 최적화

• 역추적 폭주

• 어떤 텍스트에 정규 표현식을 적용하는냐에 따라 효율성에 큰 차이

Page 19: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

2 정규 표현식 최적화

• 역추적 폭주

• 어떤 텍스트에 정규 표현식을 적용하는냐에 따라 효율성에 큰 차이

Page 20: High Performance JavaScript - Chapter 5. Strings and Regular Expressions
Page 21: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

• regular expression은 불편하므로 보통은 regex라고 줄여 쓰고 regexes라고 발음

http://ko.forvo.com/

Page 22: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

• regular expression은 불편하므로 보통은 regex라고 줄여 쓰고 regexes라고 발음

http://ko.forvo.com/

Page 23: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

정규식이 동작하는 방법

• 1단계 : 컴파일

• 2단계 : 시작 위치 결정

• 3단계 : 각각의 정규 표현식 토큰을 대조

• 4단계 : 성공 또는 실패

Page 24: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

1단계 : 컴파일

• 정규식 객체를 만들면 브라우저에서 패턴에 에러가 없는지 검사

• 실제로 매칭을 수행할 내장 코드 루틴으로 변경

• 변수에 할당하면 패턴을 한 번만 컴파일

Page 25: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

2단계 : 시작 위치 결정

• 먼저 대상 문자열의 어디부터 검색 시작할지 결정

• lastIndex 속성에서 시작 (“g” flag + test, exec)

• 4단계에서 일치 패턴을 찾지 못해서 돌아왔을 때는 마지막 시도 다음 문자

Page 26: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

3단계 : 각각의 정규식 토큰을 대조

• 텍스트와 정규식 패턴을 대조

• 토큰 중 일치하지 않는 것이 있으면 앞 지점으로 역추적 시도

Page 27: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

4단계 : 성공 또는 실패

• 완전히 일치하는 패턴을 찾으면 성공

• 아니라면 2단계로 돌아가서 그 다음 문자부터 다시 시작

• 문자열의 마지막까지 일치하는 패턴을 못찾을 때만 실패 선언

Page 28: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

역추적 이해하기

• 계산을 많이 해야 하고, 쉽게 통제를 벗어나기도

• 수량자나 or 연산자를 만날 때 어떻게 진행할지 결정이 필요 (여러 옵션이 존재하게 됨)

• 이후 패턴에서 실패하면 시도해보지 않은 옵션이 있는 마지막 지점까지 역추적!

Page 29: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

or 연산자와 역추적/h(ello|appy) hippo/.test("hello there, happy hippo");

Page 30: High Performance JavaScript - Chapter 5. Strings and Regular Expressions
Page 31: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/h(ello|appy) hippo/ "hello there, happy hippo"

Page 32: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

Page 33: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

Page 34: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

Page 35: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

Page 36: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

Page 37: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

Page 38: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

Page 39: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

Page 40: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

...

Page 41: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

/h(ello|appy) hippo/ "hello there, happy hippo"

...

/h(ello|appy) hippo/ "hello there, happy hippo"

Page 42: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

반복과 역추적

var str = "<p>Para 1.</p>" + "<img src = 'smileY.jpg'>" + "<p>Para 2.</p>" + "<div>Div.</div>";

/<p>.*<\/p>/i.test(str);

Page 43: High Performance JavaScript - Chapter 5. Strings and Regular Expressions
Page 44: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

Page 45: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 46: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 47: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 48: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 49: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 50: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 51: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 52: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 53: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 54: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 55: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 56: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

/<p>.*</p>/ “<p>Para 1.</p>”

Page 57: High Performance JavaScript - Chapter 5. Strings and Regular Expressions
Page 58: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

역추적 폭주

• 올바른 HTML 문자열에서 문제가 없지만

• 필수 태그를 생략했을 경우 매우 심각한 문제

/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

Page 59: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

역추적 폭주/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

<html> <head> <meta charset=”utf-8” /> <title>JS Bin</title> </head> <body> <div>Lorem ipsum dolor sit</div> </body></html>

Page 60: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

역추적 폭주/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

<html> <head> <meta charset=”utf-8” /> <title>JS Bin</title> </head> <body> <div>Lorem ipsum dolor sit</div> </body>

Page 61: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

역추적 폭주/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

<html> <head> <meta charset=”utf-8” /> <title>JS Bin</title> </head> <body> <div>Lorem ipsum dolor sit</div> </body>

Page 62: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

역추적 폭주/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

<html> <head> <meta charset=”utf-8” /> <title>JS Bin</title> </head> <body> <div>Lorem ipsum dolor sit</div> </body>

비교 위치역추적!!!

Page 63: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

역추적 폭주/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

<html> <head> <meta charset=”utf-8” /> <title>JS Bin</title> </head> <body> <div>Lorem ipsum dolor sit</div> </body>

Page 64: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

역추적 폭주/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

<html> <head> <meta charset=”utf-8” /> <title>JS Bin</title> </head> <body> <div>Lorem ipsum dolor sit</div> </body>

Page 65: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

역추적 폭주/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

<html> <head> <meta charset=”utf-8” /> <title>JS Bin</title> </head> <body> <div>Lorem ipsum dolor sit</div> </body>

Page 66: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

역추적 폭주/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

<html> <head> <meta charset=”utf-8” /> <title>JS Bin</title> </head> <body> <div>Lorem ipsum dolor sit</div> </body>

Page 67: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

역추적 폭주

• 정규 표현식이 느려지는 이유는

• “일치하는 것을 찾는” 데 시간이 걸려서가 아닌

• “일치하지 않는다고 판단”하는데 시간이 걸리기 때문

Page 68: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

해결책

• 필수적인 구분 기호 사이에 들어가는, 정규 표현식과 일치시킬 문자를 가능한 한 명확하게 써야

/“.*?”/ ⇒ /“[^”\r\n]*”/

Page 69: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

해결책

• 하지만, 부정형 룩어헤드 때문에 비효율적

/<html>(?:(?!<head>)[\s\S])*<head>(?:(?!<title>)[\s\S])*<title>(?:(?!<\/title>)[\s\S])*<\/title>(?:(?!<\/head>)[\s\S])*<\/head>(?:(?!<body>)[\s\S])*<body>(?:(?!<\/body>)[\s\S])*<\/body>(?:(?!<\/html>)[\s\S])*<\/html>/

Page 70: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

룩어헤드와 역참조를 써서 최소 그룹 흉내내기

• (?>...) 최소 그룹 패턴

• 역추적하지 않는 부분식(적극적 부분식)

• 부분식이 완전히 일치하면 역추적에 참여하지 않음

Page 71: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

룩어헤드와 역참조를 써서 최소 그룹 흉내내기

• (?>...) 최소 그룹 패턴

• 역추적하지 않는 부분식(적극적 부분식)

• 부분식이 완전히 일치하면 역추적에 참여하지 않음

• JavaScript는 지원하지 않는다!

Page 72: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

룩어헤드와 역참조를 써서 최소 그룹 흉내내기

(?=(최소 그룹으로 만들 패턴))\1

var str = "<p>Para 1.</p>", reg1 = /<p>([\s\S]*?<\/p>)/, // 캡처함. 룩어헤드 없음 reg2 = /<p>(?=([\s\S]*?<\/p>))/, // 캡처 + 룩어헤드. 역참조 없음 reg3 = /<p>(?=([\s\S]*?<\/p>))\1/; // 캡처 + 룩어헤드 + 역잠조

alert(reg1.exec(str)); // ["<p>Para 1.</p>", "Para 1.</p>"]alert(reg2.exec(str)); // ["<p>", "Para 1.</p>"]alert(reg3.exec(str)); // ["<p>Para 1.</p>", "Para 1.</p>"]

Page 73: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

다시 보는 역추적 폭주/<html>[\s\S]*?<head>[\s\S]*?<title>[\s\S]*?<\/title>[\s\S]*?<\/head>[\s\S]*?<body>[\s\S]*?<\/body>[\s\S]*?<\/html>/

<html> <head> <meta charset=”utf-8” /> <title>JS Bin</title> </head> <body> <div>Lorem ipsum dolor sit</div> </body>

비교 위치역추적!!!

Page 74: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

룩어헤드와 역참조를 써서 최소 그룹 흉내내기

/<html>(?=([\s\S]*?<head>))\1(?=([\s\S]*?<title>))\2(?=([\s\S]*?<\/title>))\3(?=([\s\S]*?<\/head>))\4(?=([\s\S]*?<body>))\5(?=([\s\S]*?<\/body>))\6[\s\S]*?<\/html>/

<html> <head> <meta charset=”utf-8” /> <title>JS Bin</title> </head> <body> <div>Lorem ipsum dolor sit</div> </body>

Page 75: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

중첩된 수량자와 역추적 폭주

• 수량자를 중첩시킬 경우 역추적이 폭주할 가능성이 크므로 항상 조심 (x+)*

• < 다음에 있는 문자를 일치시킬 경우의 수가 매우 많아져서 역추적 폭주 가능성

/<(?:[^>"']|"[^"]*"|'[^']*')*>/

Page 76: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

중첩된 수량자와 역추적 폭주

/(A+A+)+B/.test("AAAAAAAAAA")

Page 77: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

중첩된 수량자와 역추적 폭주

/(A+A+)+B/.test("AAAAAAAAAA")

첫 번째 A+가 8개 의 문자와 일치하고 두 번째 A十가 2개의 문자와 일치한다변 어떨까요? 아니면 첫 번째 A+가 3 개의 문자와 일치하고 두 번째 A+가 2개의 문자와 일치하면서 이 그룹이 두 번 반복한 것이라면? 그룹을 처음 처리할 때는 첫 번째 A+가 2개의 문자와 일치하고 두 번째 A+가 3개의 문자와 일치 한 다음, 두 번째 처리할 때는 첫 번째 A+가 1개의 문자와 일치하고 두 번째 A+가 4개의 문자와 일치한 것이라면?

Page 78: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

중첩된 수량자와 역추적 폭주

/(A+A+)+B/.test("AAAAAAAAAA")

첫 번째 A+가 8개 의 문자와 일치하고 두 번째 A十가 2개의 문자와 일치한다변 어떨까요? 아니면 첫 번째 A+가 3 개의 문자와 일치하고 두 번째 A+가 2개의 문자와 일치하면서 이 그룹이 두 번 반복한 것이라면? 그룹을 처음 처리할 때는 첫 번째 A+가 2개의 문자와 일치하고 두 번째 A+가 3개의 문자와 일치 한 다음, 두 번째 처리할 때는 첫 번째 A+가 1개의 문자와 일치하고 두 번째 A+가 4개의 문자와 일치한 것이라면?

n = 문자열 길이2^n 계산

“AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA” = 34,359,738,368번

Page 79: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

벤치마크 시 참고할 것

Page 80: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

벤치마크 시 참고할 것

• 정규 표현식 성능은 어떤 문자열에 적용하느냐에 따라 천차만별

Page 81: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

벤치마크 시 참고할 것

• 정규 표현식 성능은 어떤 문자열에 적용하느냐에 따라 천차만별

• 문자열을 다양한 길이로 만들면서 검사해야

Page 82: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

벤치마크 시 참고할 것

• 정규 표현식 성능은 어떤 문자열에 적용하느냐에 따라 천차만별

• 문자열을 다양한 길이로 만들면서 검사해야

• 역추적 폭주 예상이 중요

• 부분적으로 일치하는 긴 문자열로 시험

Page 83: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

효율성을 올리는 더 많은 방법

• 실패할 거라면 되도록 일찍 실패하게 만드십시오

• 단순하고 꼭 필요한 토큰으로 시작하십시오

• 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오

• or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오

• 캡처하지 않는 그룹을 사용하십시오

• 재사용할 텍스트를 캡처해서 후처리를 줄이십시오

• 필수적인 토큰을 드러내십시오

• 적합한 수량자를 쓰십시오

• 정규 표현식을 변수에 할당해서 재사용하십시오

• 복잡한 정규 표현식을 간단한 조각으로 나누십시오

Page 84: High Performance JavaScript - Chapter 5. Strings and Regular Expressions
Page 85: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

효율성을 올리는 더 많은 방법

• 실패할 거라면 되도록 일찍 실패하게 만드십시오

• 단순하고 꼭 필요한 토큰으로 시작하십시오

• 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오

• or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오

• 캡처하지 않는 그룹을 사용하십시오

• 재사용할 텍스트를 캡처해서 후처리를 줄이십시오

• 필수적인 토큰을 드러내십시오

• 적합한 수량자를 쓰십시오

• 정규 표현식을 변수에 할당해서 재사용하십시오

• 복잡한 정규 표현식을 간단한 조각으로 나누십시오

[^”\r\n]* ⇏ .*?

Page 86: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

효율성을 올리는 더 많은 방법

• 실패할 거라면 되도록 일찍 실패하게 만드십시오

• 단순하고 꼭 필요한 토큰으로 시작하십시오

• 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오

• or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오

• 캡처하지 않는 그룹을 사용하십시오

• 재사용할 텍스트를 캡처해서 후처리를 줄이십시오

• 필수적인 토큰을 드러내십시오

• 적합한 수량자를 쓰십시오

• 정규 표현식을 변수에 할당해서 재사용하십시오

• 복잡한 정규 표현식을 간단한 조각으로 나누십시오

이것 대신 이걸 씁니다

cat|bat [cb]at

red|read rea?d

red|raw r(?:ed|aw)

(.|\r|\n) [\s\S]

Page 87: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

효율성을 올리는 더 많은 방법

• 실패할 거라면 되도록 일찍 실패하게 만드십시오

• 단순하고 꼭 필요한 토큰으로 시작하십시오

• 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오

• or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오

• 캡처하지 않는 그룹을 사용하십시오

• 재사용할 텍스트를 캡처해서 후처리를 줄이십시오

• 필수적인 토큰을 드러내십시오

• 적합한 수량자를 쓰십시오

• 정규 표현식을 변수에 할당해서 재사용하십시오

• 복잡한 정규 표현식을 간단한 조각으로 나누십시오

/^(ab|cd)/ ⇏ /(^ab|^cd)/

Page 88: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

효율성을 올리는 더 많은 방법

• 실패할 거라면 되도록 일찍 실패하게 만드십시오

• 단순하고 꼭 필요한 토큰으로 시작하십시오

• 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오

• or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오

• 캡처하지 않는 그룹을 사용하십시오

• 재사용할 텍스트를 캡처해서 후처리를 줄이십시오

• 필수적인 토큰을 드러내십시오

• 적합한 수량자를 쓰십시오

• 정규 표현식을 변수에 할당해서 재사용하십시오

• 복잡한 정규 표현식을 간단한 조각으로 나누십시오

“괴물같은 정규 표현식은 만들지 말자!!”

Page 89: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

정규식으르 쓰지 않는 것이 좋을 때

• 찾으려는 부분이 문자열의 어디에 위치하는지 미리 안다면

• 문자열 메서드만으로 처리 가능 하다면

endsWithSemicolon = /;$/.test(str);endsWithSemicolon = str.charAt(str.length - 1) == ";";

Page 90: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

3 문자열 트리밍

• ECMAScript 5 : String.prototype.trim

• 정규 표현식 최적화 예제 단골

Page 91: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

정규식으로 트리밍 구현// trim 1if(!String.prototype.trim) { String.prototype.trim = function() { return this.replace(/^\s+/, "").replace(/\s+$/, ""); }}// 새 메서드를 테스트합니다.

// 문자열 앞 공백에 탭(\t) 문자와 줄바꿈(\n) 문자를 넣었습니다.var str = " \t\n test string ".trim();alert(str == "test string"); // "true"

Page 92: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

정규식으로 트리밍 구현

• or 연산자의 두 옵션을 문자열의 모든 위치에서 시도

// trim 2String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ""); }

Page 93: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

정규식으로 트리밍 구현

• 게으른 수량자(*?) 때문에 필요 없는 역추적이 많이 발생

// trim 3String.prototype.trim = function() { return this.replace(/^\s*([\s\S]*?)\s*$/, "$1"); }

Page 94: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

정규식으로 트리밍 구현

• 탐욕적 수량자로 변경해도 성능 향상

• 모든 문자에 일치하는 클래스를 탐욕적 수량자로 반복할 경우 특별한 최적화 (FF, Opera 9 제외)

// trim 4String.prototype.trim = function() { return this.replace(/^\s*([\s\S]*\S)?\s*$/, "$1"); }

Page 95: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

정규식으로 트리밍 구현

• 지금까지 예시 중 가장 느림

• 내부 그룹이 한번에 한 단어씩 수량자 중첩 상태

// trim 5String.prototype.trim = function() { return this.replace(/^\s*(\S*(\s+\S+)*)\s*$/, "$1"); }

Page 96: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

정규식 없이 트리밍 구현// trim 6String.prototype.trim = function() { var start = 0, end = this.length - 1, ws = " \n\r\t\f\x0b\xa0\u1680\u180e\u2000\u2001\u2002 \u2003\u2003\u2004\u2005\u2006\u2007\u2008\u2009 \u200a\u200b\u2028\u2029\u202f\u205f\u3000\ufeff";

while(ws.indexOf(this.charAt(start)) > -1) { start++; } while(end > start && ws.indexOf(this.charAt(end)) > -1) { end--; }

return this.slice(start, end + 1);}

Page 97: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

정규식 없이 트리밍 구현

• 정규식은 중간에 문자를 고려하지 않고 맨 뒤로 건너뛸 수 없음

• 이 경우 두 번째 while 문이 문자열 맨 뒤에서 시작

• 앞뒤 공백의 길이가 길면 성능 저하

Page 98: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

장점만 취한 해결책

// trim 7String.prototype.trim = function() { var str = this.replace(/^\s+/, ""), end = str.length - 1, ws = /\s/;

while(ws.test(str.charAt(end))) { end--; } return str.slice(0, end + 1);}

Page 99: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

결과

Page 100: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

결과

Page 101: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

4 요약• 문자열을 매우 많이 합치거나 큰 문자열을 합칠 때 인터넷 익스플로러 7과 이전 버전에서 무난한 성능을 내

려면 배열 병합이 유일한 방법입니다.

• 인터넷 익스플로러 7과 이전 버전을 지원할 필요가 없다면 문자열을 합치는 방법 중 가장 느린 배열 병합을 쓸 필요는 없습니다. 단순한 + 연산자와 += 연산자를 쓰고 불필요한 중간 단계의 문자열을 없애십시오.

• 역추적은 정규 표현식의 기본적인 구성 요소지만 비효율의 원인이 될 때가 잦습니다.

• 보통은 일치하는 것을 빠르게 찾아냈을 정규 표현식도 역추적이 폭주하면 느리게 동작하며 부분적으로 일치하는 문자열에 적용했을 때는 브라우저를 멈추게 할 수 있습니다. 인접한 토큰을 상호배타적으로 만들고, 중첩된 수량자가 같은 부분에 일치하지 않게 만들고, 룩어헤드를 최소 그룹처럼 동작하게 해서 불필요한 역추적을 없애면 이런 문제를 피할 수 있습니다.

• 일치하는 부분을 빨리 찾을 수 있게 만들고 일치하지 않는 부분에서 시간을 덜 소비하게 하는 방법이 여러가지 있습니다 (“정규 표현식의 효율성을 올리는 더 많은 방법”을 보십시오).

• 정규 표현식이 항상 최선의 수단인 것은 아니며 특히 리터럴 문자열을 찾으려 할 때는 정규 표현식을 쓰지 않아도 됩니다.

• 여러 가지 방법으로 문자열의 앞뒤 공백을 잘라낼 수 있지만 두 개의 단순한 정규 표현식을 써서 하나는 문자열 앞의 공백문자를 제거하고 다른 하나는 문자열 뒤의 공백문자를 잘라내도록 하면 간결한 코드로도 문자열의 길이나 구성에 구애받지 않고 다양한 브라우저에서 효율적이게 할 수 있습니다. 반복문을 써서 문자열의 맨 뒤에서부터 공백 아닌 마지막 문자까지 거슬러 올라가게 하거나 이 방법을 정규 표현식과 결합하면 문자열의 전체 길이에 별 영향을 받지 않습니다.

Page 102: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

4 요약• 문자열을 매우 많이 합치거나 큰 문자열을 합칠 때 인터넷 익스플로러 7과 이전 버전에서 무난한 성능을 내

려면 배열 병합이 유일한 방법입니다.

• 인터넷 익스플로러 7과 이전 버전을 지원할 필요가 없다면 문자열을 합치는 방법 중 가장 느린 배열 병합을 쓸 필요는 없습니다. 단순한 + 연산자와 += 연산자를 쓰고 불필요한 중간 단계의 문자열을 없애십시오.

• 역추적은 정규 표현식의 기본적인 구성 요소지만 비효율의 원인이 될 때가 잦습니다.

• 보통은 일치하는 것을 빠르게 찾아냈을 정규 표현식도 역추적이 폭주하면 느리게 동작하며 부분적으로 일치하는 문자열에 적용했을 때는 브라우저를 멈추게 할 수 있습니다. 인접한 토큰을 상호배타적으로 만들고, 중첩된 수량자가 같은 부분에 일치하지 않게 만들고, 룩어헤드를 최소 그룹처럼 동작하게 해서 불필요한 역추적을 없애면 이런 문제를 피할 수 있습니다.

• 일치하는 부분을 빨리 찾을 수 있게 만들고 일치하지 않는 부분에서 시간을 덜 소비하게 하는 방법이 여러가지 있습니다 (“정규 표현식의 효율성을 올리는 더 많은 방법”을 보십시오).

• 정규 표현식이 항상 최선의 수단인 것은 아니며 특히 리터럴 문자열을 찾으려 할 때는 정규 표현식을 쓰지 않아도 됩니다.

• 여러 가지 방법으로 문자열의 앞뒤 공백을 잘라낼 수 있지만 두 개의 단순한 정규 표현식을 써서 하나는 문자열 앞의 공백문자를 제거하고 다른 하나는 문자열 뒤의 공백문자를 잘라내도록 하면 간결한 코드로도 문자열의 길이나 구성에 구애받지 않고 다양한 브라우저에서 효율적이게 할 수 있습니다. 반복문을 써서 문자열의 맨 뒤에서부터 공백 아닌 마지막 문자까지 거슬러 올라가게 하거나 이 방법을 정규 표현식과 결합하면 문자열의 전체 길이에 별 영향을 받지 않습니다.

Page 103: High Performance JavaScript - Chapter 5. Strings and Regular Expressions

주관적인 요약

• 모던 브라우저는 충분히 빠르다. (즉, 하위 브라우저에서 효율성 테스트면 충분할지도)

• 정규 표현식 동작 과정과 역추적 정도는 알고 있어야 한다.

• 정규 표현식이 최선의 수단은 아니다.