SlideShare a Scribd company logo
1 of 103
Download to read offline
5
문자열과 정규 표현식
High Performance JavaScript
시작하면서..

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

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

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

•   Steven Levithan : http://blog.stevenlevithan.com/
1 문자열 병합


• 매우 성능에 민감할 수 있다.
• 루프 + 문자열 병합
문자열 병합 방법
방법                예제


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

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

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

                  str = “a”;
string.concat()
                  str = str.concat(“b”, “c”);
+ 연산자 & += 연산자


• 가장 간편한 방법
• 모던 브라우저는 충분히 최적화 (IE > 7)
+ 연산자 & += 연산자
     str += “one” + “two”;


1. 메모리에 임시 문자열이 만들어집니다.
2. 병합된 문자열 “onetwo"를 임시 문자열에 할당합니다.
3. 임시 문자열과 str 변수의 현재 값을 합칩니다.
4. 결과를 str에 저장합니다.
+ 연산자 & += 연산자
       str += “one”;
       str += “two”;


• 임시 문자열 부분을 제거
• 대부분 브라우저에서 10~40% 향상
+ 연산자 & += 연산자

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

// str = ((str + “one”) + “two”)와 같습니다.
+ 연산자 & += 연산자
+ 연산자 & += 연산자
• 앞의 테크닉은 IE에서 적용되지 않음
• IE8 경우
 • 병합할 때 각 부분 문자열의 참조만 저장
 • 합쳐진 문자열이 실제로 쓰일때 “진짜” 문자
   열에 복사되어 사용

 • toString(), length, DOM 추가
+ 연산자 & += 연산자

• IE7 이하
 • 매번 문자열을 메모리 새 위치에 복사
  largeStr = largeStr + s1 + s2;
  largeStr += s1 + s2; // 빠름
파이어폭스와 컴파일 타임 폴딩

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";
} */
배열 병합


• Array.prototype.join
• IE7 이하에서만 효과적
배열 병합
var str = "I'm a thirty-five character string.",
    newStr = "",
    appends = 5000;

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

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

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

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

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

• 대부분 브라우저에서 느린편
• 배열 매개변수 사용 ≠ 배열 병합
• IE7 이하 엄청난 성능 저하
2 정규 표현식 최적화

• 역추적 폭주
• 어떤 텍스트에 정규 표현식을 적용하는냐에
 따라 효율성에 큰 차이
2 정규 표현식 최적화

• 역추적 폭주
• 어떤 텍스트에 정규 표현식을 적용하는냐에
 따라 효율성에 큰 차이
• regular expression은 불편하므로 보통은
 regex라고 줄여 쓰고 regexes라고 발음




            http://ko.forvo.com/
• regular expression은 불편하므로 보통은
 regex라고 줄여 쓰고 regexes라고 발음




            http://ko.forvo.com/
정규식이 동작하는 방법

• 1단계 : 컴파일
• 2단계 : 시작 위치 결정
• 3단계 : 각각의 정규 표현식 토큰을 대조
• 4단계 : 성공 또는 실패
1단계 : 컴파일

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

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

• 변수에 할당하면 패턴을 한 번만 컴파일
2단계 : 시작 위치 결정

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

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

• 4단계에서 일치 패턴을 찾지 못해서 돌아왔을
 때는 마지막 시도 다음 문자
3단계 : 각각의 정규식 토큰을 대조



• 텍스트와 정규식 패턴을 대조
• 토큰 중 일치하지 않는 것이 있으면 앞 지점으
 로 역추적 시도
4단계 : 성공 또는 실패

• 완전히 일치하는 패턴을 찾으면 성공
• 아니라면 2단계로 돌아가서 그 다음 문자부터
 다시 시작

• 문자열의 마지막까지 일치하는 패턴을 못찾을
 때만 실패 선언
역추적 이해하기

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

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

•   이후 패턴에서 실패하면 시도해보지 않은 옵션이
    있는 마지막 지점까지 역추적!
or 연산자와 역추적
/h(ello|appy) hippo/.test("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"
/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"
/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"
/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"
/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"
/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"
/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"
반복과 역추적
var str = "<p>Para 1.</p>" +
          "<img src = 'smileY.jpg'>" +
          "<p>Para 2.</p>" +
          "<div>Div.</div>";

/<p>.*</p>/i.test(str);
/<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>”
/<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>”
/<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>”
/<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>”
/<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>”
/<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>”
/<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>”
역추적 폭주
/
<html>
[sS]*?<head>
[sS]*?<title>
[sS]*?</title>
[sS]*?</head>
[sS]*?<body>      •   올바른 HTML 문자열에서 문제가 없지만

                    •
[sS]*?</body>
[sS]*?</html>        필수 태그를 생략했을 경우 매우 심각한 문제
/
역추적 폭주
/
                     <html>
<html>
                       <head>
[sS]*?<head>
                         <meta charset=”utf-8” />
[sS]*?<title>
                         <title>JS Bin</title>
[sS]*?</title>
                       </head>
[sS]*?</head>
                       <body>
[sS]*?<body>
                         <div>Lorem ipsum dolor sit</div>
[sS]*?</body>
                       </body>
[sS]*?</html>
                     </html>
/
역추적 폭주
/
<html>               <html>
[sS]*?<head>         <head>
[sS]*?<title>          <meta charset=”utf-8” />
[sS]*?</title>        <title>JS Bin</title>
[sS]*?</head>       </head>
[sS]*?<body>         <body>
[sS]*?</body>         <div>Lorem ipsum dolor sit</div>
[sS]*?</html>       </body>
/
역추적 폭주
/
<html>               <html>
[sS]*?<head>         <head>
[sS]*?<title>          <meta charset=”utf-8” />
[sS]*?</title>        <title>JS Bin</title>
[sS]*?</head>       </head>
[sS]*?<body>         <body>
[sS]*?</body>         <div>Lorem ipsum dolor sit</div>
[sS]*?</html>       </body>
/
역추적 폭주
/
<html>               <html>
[sS]*?<head>         <head>
[sS]*?<title>          <meta charset=”utf-8” />
[sS]*?</title>        <title>JS Bin</title>
[sS]*?</head>       </head>
[sS]*?<body>         <body>
[sS]*?</body>         <div>Lorem ipsum dolor sit</div>
[sS]*?</html>       </body>
/

      역추적!!!             비교 위치
역추적 폭주
/
<html>               <html>
[sS]*?<head>         <head>
[sS]*?<title>          <meta charset=”utf-8” />
[sS]*?</title>        <title>JS Bin</title>
[sS]*?</head>       </head>
[sS]*?<body>         <body>
[sS]*?</body>         <div>Lorem ipsum dolor sit</div>
[sS]*?</html>       </body>
/
역추적 폭주
/
<html>               <html>
[sS]*?<head>         <head>
[sS]*?<title>          <meta charset=”utf-8” />
[sS]*?</title>        <title>JS Bin</title>
[sS]*?</head>       </head>
[sS]*?<body>         <body>
[sS]*?</body>         <div>Lorem ipsum dolor sit</div>
[sS]*?</html>       </body>
/
역추적 폭주
/
<html>               <html>
[sS]*?<head>         <head>
[sS]*?<title>          <meta charset=”utf-8” />
[sS]*?</title>        <title>JS Bin</title>
[sS]*?</head>       </head>
[sS]*?<body>         <body>
[sS]*?</body>         <div>Lorem ipsum dolor sit</div>
[sS]*?</html>       </body>
/
역추적 폭주
/
<html>               <html>
[sS]*?<head>         <head>
[sS]*?<title>          <meta charset=”utf-8” />
[sS]*?</title>        <title>JS Bin</title>
[sS]*?</head>       </head>
[sS]*?<body>         <body>
[sS]*?</body>         <div>Lorem ipsum dolor sit</div>
[sS]*?</html>       </body>
/
역추적 폭주


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

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

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

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

  /“.*?”/   ⇒   /“[^”rn]*”/
해결책
/
<html>
(?:(?!<head>)[sS])*<head>
(?:(?!<title>)[sS])*<title>
(?:(?!</title>)[sS])*</title>
(?:(?!</head>)[sS])*</head>
(?:(?!<body>)[sS])*<body>
(?:(?!</body>)[sS])*</body>
(?:(?!</html>)[sS])*</html>
/



 •   하지만, 부정형 룩어헤드 때문에 비효율적
룩어헤드와 역참조를 써서 최소 그룹 흉내내기



• (?>...) 최소 그룹 패턴
 • 역추적하지 않는 부분식(적극적 부분식)
 • 부분식이 완전히 일치하면 역추적에 참여하
  지 않음
룩어헤드와 역참조를 써서 최소 그룹 흉내내기



• (?>...) 최소 그룹 패턴
 • 역추적하지 않는 부분식(적극적 부분식)
 • 부분식이 완전히 일치하면 역추적에 참여하
   지 않음

• JavaScript는 지원하지 않는다!
룩어헤드와 역참조를 써서 최소 그룹 흉내내기

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


var str = "<p>Para 1.</p>",
    reg1 = /<p>([sS]*?</p>)/,         // 캡처함. 룩어헤드 없음
    reg2 = /<p>(?=([sS]*?</p>))/,     // 캡처 + 룩어헤드. 역참조 없음
    reg3 = /<p>(?=([sS]*?</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>"]
다시 보는 역추적 폭주
/
<html>              <html>
[sS]*?<head>        <head>
[sS]*?<title>         <meta charset=”utf-8” />
[sS]*?</title>       <title>JS Bin</title>
[sS]*?</head>      </head>
[sS]*?<body>        <body>
[sS]*?</body>        <div>Lorem ipsum dolor sit</div>
[sS]*?</html>      </body>
/

      역추적!!!            비교 위치
룩어헤드와 역참조를 써서 최소 그룹 흉내내기


/
<html>                      <html>
(?=([sS]*?<head>))1        <head>
(?=([sS]*?<title>))2         <meta charset=”utf-8” />
(?=([sS]*?</title>))3       <title>JS Bin</title>
(?=([sS]*?</head>))4      </head>
(?=([sS]*?<body>))5        <body>
(?=([sS]*?</body>))6        <div>Lorem ipsum dolor sit</div>
[sS]*?</html>              </body>
/
중첩된 수량자와 역추적 폭주

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


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

• < 다음에 있는 문자를 일치시킬 경우의 수가
 매우 많아져서 역추적 폭주 가능성
중첩된 수량자와 역추적 폭주
 /(A+A+)+B/.test("AAAAAAAAAA")
중첩된 수량자와 역추적 폭주
       /(A+A+)+B/.test("AAAAAAAAAA")

첫 번째 A+가 8개 의 문자와 일치하고 두 번째 A十가 2개의 문자와 일치한다변 어떨까요?
아니면 첫 번째 A+가 3 개의 문자와 일치하고 두 번째 A+가 2개의 문자와 일치하면서 이 그룹이 두 번
반복한 것이라면?
그룹을 처음 처리할 때는 첫 번째 A+가 2개의 문자와 일치하고 두 번째 A+가 3개의 문자와 일치 한 다
음, 두 번째 처리할 때는 첫 번째 A+가 1개의 문자와 일치하고 두 번째 A+가 4개의 문자와 일치한 것이라
면?
중첩된 수량자와 역추적 폭주
          /(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번
벤치마크 시 참고할 것
벤치마크 시 참고할 것

• 정규 표현식 성능은 어떤 문자열에 적용하느
 냐에 따라 천차만별
벤치마크 시 참고할 것

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

• 문자열을 다양한 길이로 만들면서 검사해야
벤치마크 시 참고할 것

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

• 문자열을 다양한 길이로 만들면서 검사해야
• 역추적 폭주 예상이 중요
 • 부분적으로 일치하는 긴 문자열로 시험
효율성을 올리는 더 많은 방법
•   실패할 거라면 되도록 일찍 실패하게 만드십시오

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

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

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

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

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

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

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

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

•   복잡한 정규 표현식을 간단한 조각으로 나누십시오
효율성을 올리는 더 많은 방법
• 실패할 거라면 되도록 일찍 실패하게 만드십시오
• 단순하고 꼭 필요한 토큰으로 시작하십시오
• 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오
• or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오
  [^”rn]* ⇏ .*?
• 캡처하지 않는 그룹을 사용하십시오
• 재사용할 텍스트를 캡처해서 후처리를 줄이십시오
• 필수적인 토큰을 드러내십시오
• 적합한 수량자를 쓰십시오
• 정규 표현식을 변수에 할당해서 재사용하십시오
• 복잡한 정규 표현식을 간단한 조각으로 나누십시오
효율성을 올리는 더 많은 방법
•   실패할 거라면 되도록 일찍 실패하게 만드십시오

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

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

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

•   캡처하지 않는 그룹을 사용하십시오
         이것 대신             이걸 씁니다
•   재사용할 텍스트를 캡처해서 후처리를 줄이십시오
         cat|bat             [cb]at
•   필수적인 토큰을 드러내십시오
         red|read            rea?d
•   적합한 수량자를 쓰십시오
         red|raw         r(?:ed|aw)
•   정규 표현식을 변수에 할당해서 재사용하십시오

•        (.|r|n)         [sS]
    복잡한 정규 표현식을 간단한 조각으로 나누십시오
효율성을 올리는 더 많은 방법
• 실패할 거라면 되도록 일찍 실패하게 만드십시오
• 단순하고 꼭 필요한 토큰으로 시작하십시오
• 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오
• or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오
/^(ab|cd)/ ⇏
• 캡처하지 않는 그룹을 사용하십시오 /(^ab|^cd)/
• 재사용할 텍스트를 캡처해서 후처리를 줄이십시오
• 필수적인 토큰을 드러내십시오
• 적합한 수량자를 쓰십시오
• 정규 표현식을 변수에 할당해서 재사용하십시오
• 복잡한 정규 표현식을 간단한 조각으로 나누십시오
효율성을 올리는 더 많은 방법
• 실패할 거라면 되도록 일찍 실패하게 만드십시오
• 단순하고 꼭 필요한 토큰으로 시작하십시오
• 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오
• or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오
• 캡처하지 않는 그룹을 사용하십시오
• 재사용할 텍스트를 캡처해서 후처리를 줄이십시오
• 필수적인 토큰을 드러내십시오
• “괴물같은 정규 표현식은 만들지 말자!!”
   적합한 수량자를 쓰십시오

• 정규 표현식을 변수에 할당해서 재사용하십시오
• 복잡한 정규 표현식을 간단한 조각으로 나누십시오
정규식으르 쓰지 않는 것이 좋을 때


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

• 문자열 메서드만으로 처리 가능 하다면
endsWithSemicolon = /;$/.test(str);
endsWithSemicolon = str.charAt(str.length - 1) == ";";
3 문자열 트리밍


• ECMAScript 5 : String.prototype.trim
• 정규 표현식 최적화 예제 단골
정규식으로 트리밍 구현
// trim 1
if(!String.prototype.trim) {
    String.prototype.trim = function() {
        return this.replace(/^s+/, "").replace(/s+$/, "");
    }
}
// 새 메서드를 테스트합니다.

// 문자열 앞 공백에 탭(t) 문자와 줄바꿈(n) 문자를 넣었습니다.
var str = " tn test string ".trim();
alert(str == "test string"); // "true"
정규식으로 트리밍 구현
// trim 2
String.prototype.trim = function() {
    return this.replace(/^s+|s+$/g, "");
}




    •   or 연산자의 두 옵션을 문자열의 모든 위치에서 시도
정규식으로 트리밍 구현
// trim 3
String.prototype.trim = function() {
    return this.replace(/^s*([sS]*?)s*$/, "$1");
}




    •   게으른 수량자(*?) 때문에 필요 없는 역추적이 많이 발생
정규식으로 트리밍 구현
// trim 4
String.prototype.trim = function() {
    return this.replace(/^s*([sS]*S)?s*$/, "$1");
}


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

    •   모든 문자에 일치하는 클래스를 탐욕적 수량자로 반복할 경
        우 특별한 최적화 (FF, Opera 9 제외)
정규식으로 트리밍 구현
// trim 5
String.prototype.trim = function() {
    return this.replace(/^s*(S*(s+S+)*)s*$/, "$1");
}



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

    •   내부 그룹이 한번에 한 단어씩 수량자 중첩 상태
정규식 없이 트리밍 구현
// trim 6
String.prototype.trim = function() {
  var start = 0,
      end = this.length - 1,
      ws = " nrtfx0bxa0u1680u180eu2000u2001u2002
           u2003u2003u2004u2005u2006u2007u2008u2009
           u200au200bu2028u2029u202fu205fu3000ufeff";

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

    return this.slice(start, end + 1);
}
정규식 없이 트리밍 구현

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

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

• 앞뒤 공백의 길이가 길면 성능 저하
장점만 취한 해결책
// trim 7
String.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);
}
결과
결과
4 요약
•   문자열을 매우 많이 합치거나 큰 문자열을 합칠 때 인터넷 익스플로러 7과 이전 버전에서 무난한 성능을 내
    려면 배열 병합이 유일한 방법입니다.

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

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

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

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

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

•   여러 가지 방법으로 문자열의 앞뒤 공백을 잘라낼 수 있지만 두 개의 단순한 정규 표현식을 써서 하나는 문
    자열 앞의 공백문자를 제거하고 다른 하나는 문자열 뒤의 공백문자를 잘라내도록 하면 간결한 코드로도 문
    자열의 길이나 구성에 구애받지 않고 다양한 브라우저에서 효율적이게 할 수 있습니다. 반복문을 써서 문자
    열의 맨 뒤에서부터 공백 아닌 마지막 문자까지 거슬러 올라가게 하거나 이 방법을 정규 표현식과 결합하면
    문자열의 전체 길이에 별 영향을 받지 않습니다.
4 요약
•   문자열을 매우 많이 합치거나 큰 문자열을 합칠 때 인터넷 익스플로러 7과 이전 버전에서 무난한 성능을 내
    려면 배열 병합이 유일한 방법입니다.

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

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

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

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

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

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

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

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

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

More Related Content

Featured

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by HubspotMarius Sescu
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 

Featured (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

High Performance JavaScript - Chapter 5. Strings and Regular Expressions

  • 1. 5 문자열과 정규 표현식 High Performance JavaScript
  • 2. 시작하면서.. • 모든 브라우저에서 동작하면서 빠르게 문자열을 조작 • 역추적을 줄여 정규 표현식 성능을 올리는 방법 • 기타 문자열과 정규 표현식을 효율적으로 쓰는 방법 • Steven Levithan : http://blog.stevenlevithan.com/
  • 3. 1 문자열 병합 • 매우 성능에 민감할 수 있다. • 루프 + 문자열 병합
  • 4. 문자열 병합 방법 방법 예제 + 연산자 str = “a” + “b” + “c”; str = “a”; += 연산자 str += “b”; array.join() str = [“a”, “b”, “c”].join(“”); str = “a”; string.concat() str = str.concat(“b”, “c”);
  • 5. + 연산자 & += 연산자 • 가장 간편한 방법 • 모던 브라우저는 충분히 최적화 (IE > 7)
  • 6. + 연산자 & += 연산자 str += “one” + “two”; 1. 메모리에 임시 문자열이 만들어집니다. 2. 병합된 문자열 “onetwo"를 임시 문자열에 할당합니다. 3. 임시 문자열과 str 변수의 현재 값을 합칩니다. 4. 결과를 str에 저장합니다.
  • 7. + 연산자 & += 연산자 str += “one”; str += “two”; • 임시 문자열 부분을 제거 • 대부분 브라우저에서 10~40% 향상
  • 8. + 연산자 & += 연산자 str = str + “one” + “two”; // str = ((str + “one”) + “two”)와 같습니다.
  • 9. + 연산자 & += 연산자
  • 10. + 연산자 & += 연산자 • 앞의 테크닉은 IE에서 적용되지 않음 • IE8 경우 • 병합할 때 각 부분 문자열의 참조만 저장 • 합쳐진 문자열이 실제로 쓰일때 “진짜” 문자 열에 복사되어 사용 • toString(), length, DOM 추가
  • 11. + 연산자 & += 연산자 • IE7 이하 • 매번 문자열을 메모리 새 위치에 복사 largeStr = largeStr + s1 + s2; largeStr += s1 + s2; // 빠름
  • 12. 파이어폭스와 컴파일 타임 폴딩 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"; } */
  • 13. 배열 병합 • Array.prototype.join • IE7 이하에서만 효과적
  • 14. 배열 병합 var str = "I'm a thirty-five character string.", newStr = "", appends = 5000; while(appends--) { newStr += str; }
  • 15. 배열 병합 var str = "I'm a thirty-five character string.", strs = [], newStr, appends = 5000; while(appends--) { strs[strs.length] = str; } newStr = strs.join("");
  • 16. String.prototype.concat // 문자열 하나를 연결합니다. str = str.concat(s1); // 문자열 세 개를 연결합니다. str = str.concat(s1, s2, s3); // 매개변수 목록으로 배열을 넘기먼 배열에 포함된 문자열 전체를 연결합니다. str = String.prototype.concat.apply(str, array);
  • 17. String.prototype.concat • 대부분 브라우저에서 느린편 • 배열 매개변수 사용 ≠ 배열 병합 • IE7 이하 엄청난 성능 저하
  • 18. 2 정규 표현식 최적화 • 역추적 폭주 • 어떤 텍스트에 정규 표현식을 적용하는냐에 따라 효율성에 큰 차이
  • 19. 2 정규 표현식 최적화 • 역추적 폭주 • 어떤 텍스트에 정규 표현식을 적용하는냐에 따라 효율성에 큰 차이
  • 20.
  • 21. • regular expression은 불편하므로 보통은 regex라고 줄여 쓰고 regexes라고 발음 http://ko.forvo.com/
  • 22. • regular expression은 불편하므로 보통은 regex라고 줄여 쓰고 regexes라고 발음 http://ko.forvo.com/
  • 23. 정규식이 동작하는 방법 • 1단계 : 컴파일 • 2단계 : 시작 위치 결정 • 3단계 : 각각의 정규 표현식 토큰을 대조 • 4단계 : 성공 또는 실패
  • 24. 1단계 : 컴파일 • 정규식 객체를 만들면 브라우저에서 패턴에 에러가 없는지 검사 • 실제로 매칭을 수행할 내장 코드 루틴으로 변 경 • 변수에 할당하면 패턴을 한 번만 컴파일
  • 25. 2단계 : 시작 위치 결정 • 먼저 대상 문자열의 어디부터 검색 시작할지 결정 • lastIndex 속성에서 시작 (“g” flag + test, exec) • 4단계에서 일치 패턴을 찾지 못해서 돌아왔을 때는 마지막 시도 다음 문자
  • 26. 3단계 : 각각의 정규식 토큰을 대조 • 텍스트와 정규식 패턴을 대조 • 토큰 중 일치하지 않는 것이 있으면 앞 지점으 로 역추적 시도
  • 27. 4단계 : 성공 또는 실패 • 완전히 일치하는 패턴을 찾으면 성공 • 아니라면 2단계로 돌아가서 그 다음 문자부터 다시 시작 • 문자열의 마지막까지 일치하는 패턴을 못찾을 때만 실패 선언
  • 28. 역추적 이해하기 • 계산을 많이 해야 하고, 쉽게 통제를 벗어나기도 • 수량자나 or 연산자를 만날 때 어떻게 진행할지 결 정이 필요 (여러 옵션이 존재하게 됨) • 이후 패턴에서 실패하면 시도해보지 않은 옵션이 있는 마지막 지점까지 역추적!
  • 29. or 연산자와 역추적 /h(ello|appy) hippo/.test("hello there, happy hippo");
  • 30.
  • 31. /h(ello|appy) hippo/ "hello there, happy hippo"
  • 32. /h(ello|appy) hippo/ "hello there, happy hippo" /h(ello|appy) hippo/ "hello there, happy hippo"
  • 33. /h(ello|appy) hippo/ "hello there, happy hippo" /h(ello|appy) hippo/ "hello there, happy hippo" /h(ello|appy) hippo/ "hello there, happy hippo"
  • 34. /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"
  • 35. /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"
  • 36. /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"
  • 37. /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"
  • 38. /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"
  • 39. /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"
  • 40. /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" ...
  • 41. /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"
  • 42. 반복과 역추적 var str = "<p>Para 1.</p>" + "<img src = 'smileY.jpg'>" + "<p>Para 2.</p>" + "<div>Div.</div>"; /<p>.*</p>/i.test(str);
  • 43.
  • 44. /<p>.*</p>/ “<p>Para 1.</p>”
  • 45. /<p>.*</p>/ “<p>Para 1.</p>” /<p>.*</p>/ “<p>Para 1.</p>”
  • 46. /<p>.*</p>/ “<p>Para 1.</p>” /<p>.*</p>/ “<p>Para 1.</p>” /<p>.*</p>/ “<p>Para 1.</p>”
  • 47. /<p>.*</p>/ “<p>Para 1.</p>” /<p>.*</p>/ “<p>Para 1.</p>” /<p>.*</p>/ “<p>Para 1.</p>” /<p>.*</p>/ “<p>Para 1.</p>”
  • 48. /<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>”
  • 49. /<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>”
  • 50. /<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>”
  • 51. /<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>”
  • 52. /<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>”
  • 53. /<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>”
  • 54. /<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>”
  • 55. /<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>”
  • 56. /<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>”
  • 57.
  • 58. 역추적 폭주 / <html> [sS]*?<head> [sS]*?<title> [sS]*?</title> [sS]*?</head> [sS]*?<body> • 올바른 HTML 문자열에서 문제가 없지만 • [sS]*?</body> [sS]*?</html> 필수 태그를 생략했을 경우 매우 심각한 문제 /
  • 59. 역추적 폭주 / <html> <html> <head> [sS]*?<head> <meta charset=”utf-8” /> [sS]*?<title> <title>JS Bin</title> [sS]*?</title> </head> [sS]*?</head> <body> [sS]*?<body> <div>Lorem ipsum dolor sit</div> [sS]*?</body> </body> [sS]*?</html> </html> /
  • 60. 역추적 폭주 / <html> <html> [sS]*?<head> <head> [sS]*?<title> <meta charset=”utf-8” /> [sS]*?</title> <title>JS Bin</title> [sS]*?</head> </head> [sS]*?<body> <body> [sS]*?</body> <div>Lorem ipsum dolor sit</div> [sS]*?</html> </body> /
  • 61. 역추적 폭주 / <html> <html> [sS]*?<head> <head> [sS]*?<title> <meta charset=”utf-8” /> [sS]*?</title> <title>JS Bin</title> [sS]*?</head> </head> [sS]*?<body> <body> [sS]*?</body> <div>Lorem ipsum dolor sit</div> [sS]*?</html> </body> /
  • 62. 역추적 폭주 / <html> <html> [sS]*?<head> <head> [sS]*?<title> <meta charset=”utf-8” /> [sS]*?</title> <title>JS Bin</title> [sS]*?</head> </head> [sS]*?<body> <body> [sS]*?</body> <div>Lorem ipsum dolor sit</div> [sS]*?</html> </body> / 역추적!!! 비교 위치
  • 63. 역추적 폭주 / <html> <html> [sS]*?<head> <head> [sS]*?<title> <meta charset=”utf-8” /> [sS]*?</title> <title>JS Bin</title> [sS]*?</head> </head> [sS]*?<body> <body> [sS]*?</body> <div>Lorem ipsum dolor sit</div> [sS]*?</html> </body> /
  • 64. 역추적 폭주 / <html> <html> [sS]*?<head> <head> [sS]*?<title> <meta charset=”utf-8” /> [sS]*?</title> <title>JS Bin</title> [sS]*?</head> </head> [sS]*?<body> <body> [sS]*?</body> <div>Lorem ipsum dolor sit</div> [sS]*?</html> </body> /
  • 65. 역추적 폭주 / <html> <html> [sS]*?<head> <head> [sS]*?<title> <meta charset=”utf-8” /> [sS]*?</title> <title>JS Bin</title> [sS]*?</head> </head> [sS]*?<body> <body> [sS]*?</body> <div>Lorem ipsum dolor sit</div> [sS]*?</html> </body> /
  • 66. 역추적 폭주 / <html> <html> [sS]*?<head> <head> [sS]*?<title> <meta charset=”utf-8” /> [sS]*?</title> <title>JS Bin</title> [sS]*?</head> </head> [sS]*?<body> <body> [sS]*?</body> <div>Lorem ipsum dolor sit</div> [sS]*?</html> </body> /
  • 67. 역추적 폭주 • 정규 표현식이 느려지는 이유는 • “일치하는 것을 찾는” 데 시간이 걸려서가 아닌 • “일치하지 않는다고 판단”하는데 시간이 걸리기 때문
  • 68. 해결책 • 필수적인 구분 기호 사이에 들어가는, 정규 표 현식과 일치시킬 문자를 가능한 한 명확하게 써야 /“.*?”/ ⇒ /“[^”rn]*”/
  • 70. 룩어헤드와 역참조를 써서 최소 그룹 흉내내기 • (?>...) 최소 그룹 패턴 • 역추적하지 않는 부분식(적극적 부분식) • 부분식이 완전히 일치하면 역추적에 참여하 지 않음
  • 71. 룩어헤드와 역참조를 써서 최소 그룹 흉내내기 • (?>...) 최소 그룹 패턴 • 역추적하지 않는 부분식(적극적 부분식) • 부분식이 완전히 일치하면 역추적에 참여하 지 않음 • JavaScript는 지원하지 않는다!
  • 72. 룩어헤드와 역참조를 써서 최소 그룹 흉내내기 (?=(최소 그룹으로 만들 패턴))1 var str = "<p>Para 1.</p>", reg1 = /<p>([sS]*?</p>)/, // 캡처함. 룩어헤드 없음 reg2 = /<p>(?=([sS]*?</p>))/, // 캡처 + 룩어헤드. 역참조 없음 reg3 = /<p>(?=([sS]*?</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>"]
  • 73. 다시 보는 역추적 폭주 / <html> <html> [sS]*?<head> <head> [sS]*?<title> <meta charset=”utf-8” /> [sS]*?</title> <title>JS Bin</title> [sS]*?</head> </head> [sS]*?<body> <body> [sS]*?</body> <div>Lorem ipsum dolor sit</div> [sS]*?</html> </body> / 역추적!!! 비교 위치
  • 74. 룩어헤드와 역참조를 써서 최소 그룹 흉내내기 / <html> <html> (?=([sS]*?<head>))1 <head> (?=([sS]*?<title>))2 <meta charset=”utf-8” /> (?=([sS]*?</title>))3 <title>JS Bin</title> (?=([sS]*?</head>))4 </head> (?=([sS]*?<body>))5 <body> (?=([sS]*?</body>))6 <div>Lorem ipsum dolor sit</div> [sS]*?</html> </body> /
  • 75. 중첩된 수량자와 역추적 폭주 /<(?:[^>"']|"[^"]*"|'[^']*')*>/ • 수량자를 중첩시킬 경우 역추적이 폭주할 가 능성이 크므로 항상 조심 (x+)* • < 다음에 있는 문자를 일치시킬 경우의 수가 매우 많아져서 역추적 폭주 가능성
  • 76. 중첩된 수량자와 역추적 폭주 /(A+A+)+B/.test("AAAAAAAAAA")
  • 77. 중첩된 수량자와 역추적 폭주 /(A+A+)+B/.test("AAAAAAAAAA") 첫 번째 A+가 8개 의 문자와 일치하고 두 번째 A十가 2개의 문자와 일치한다변 어떨까요? 아니면 첫 번째 A+가 3 개의 문자와 일치하고 두 번째 A+가 2개의 문자와 일치하면서 이 그룹이 두 번 반복한 것이라면? 그룹을 처음 처리할 때는 첫 번째 A+가 2개의 문자와 일치하고 두 번째 A+가 3개의 문자와 일치 한 다 음, 두 번째 처리할 때는 첫 번째 A+가 1개의 문자와 일치하고 두 번째 A+가 4개의 문자와 일치한 것이라 면?
  • 78. 중첩된 수량자와 역추적 폭주 /(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번
  • 80. 벤치마크 시 참고할 것 • 정규 표현식 성능은 어떤 문자열에 적용하느 냐에 따라 천차만별
  • 81. 벤치마크 시 참고할 것 • 정규 표현식 성능은 어떤 문자열에 적용하느 냐에 따라 천차만별 • 문자열을 다양한 길이로 만들면서 검사해야
  • 82. 벤치마크 시 참고할 것 • 정규 표현식 성능은 어떤 문자열에 적용하느 냐에 따라 천차만별 • 문자열을 다양한 길이로 만들면서 검사해야 • 역추적 폭주 예상이 중요 • 부분적으로 일치하는 긴 문자열로 시험
  • 83. 효율성을 올리는 더 많은 방법 • 실패할 거라면 되도록 일찍 실패하게 만드십시오 • 단순하고 꼭 필요한 토큰으로 시작하십시오 • 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오 • or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오 • 캡처하지 않는 그룹을 사용하십시오 • 재사용할 텍스트를 캡처해서 후처리를 줄이십시오 • 필수적인 토큰을 드러내십시오 • 적합한 수량자를 쓰십시오 • 정규 표현식을 변수에 할당해서 재사용하십시오 • 복잡한 정규 표현식을 간단한 조각으로 나누십시오
  • 84.
  • 85. 효율성을 올리는 더 많은 방법 • 실패할 거라면 되도록 일찍 실패하게 만드십시오 • 단순하고 꼭 필요한 토큰으로 시작하십시오 • 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오 • or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오 [^”rn]* ⇏ .*? • 캡처하지 않는 그룹을 사용하십시오 • 재사용할 텍스트를 캡처해서 후처리를 줄이십시오 • 필수적인 토큰을 드러내십시오 • 적합한 수량자를 쓰십시오 • 정규 표현식을 변수에 할당해서 재사용하십시오 • 복잡한 정규 표현식을 간단한 조각으로 나누십시오
  • 86. 효율성을 올리는 더 많은 방법 • 실패할 거라면 되도록 일찍 실패하게 만드십시오 • 단순하고 꼭 필요한 토큰으로 시작하십시오 • 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오 • or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오 • 캡처하지 않는 그룹을 사용하십시오 이것 대신 이걸 씁니다 • 재사용할 텍스트를 캡처해서 후처리를 줄이십시오 cat|bat [cb]at • 필수적인 토큰을 드러내십시오 red|read rea?d • 적합한 수량자를 쓰십시오 red|raw r(?:ed|aw) • 정규 표현식을 변수에 할당해서 재사용하십시오 • (.|r|n) [sS] 복잡한 정규 표현식을 간단한 조각으로 나누십시오
  • 87. 효율성을 올리는 더 많은 방법 • 실패할 거라면 되도록 일찍 실패하게 만드십시오 • 단순하고 꼭 필요한 토큰으로 시작하십시오 • 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오 • or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오 /^(ab|cd)/ ⇏ • 캡처하지 않는 그룹을 사용하십시오 /(^ab|^cd)/ • 재사용할 텍스트를 캡처해서 후처리를 줄이십시오 • 필수적인 토큰을 드러내십시오 • 적합한 수량자를 쓰십시오 • 정규 표현식을 변수에 할당해서 재사용하십시오 • 복잡한 정규 표현식을 간단한 조각으로 나누십시오
  • 88. 효율성을 올리는 더 많은 방법 • 실패할 거라면 되도록 일찍 실패하게 만드십시오 • 단순하고 꼭 필요한 토큰으로 시작하십시오 • 수량자를 붙인 패턴과 그 뒤에 있는 토큰을 배타적으로 만드십시오 • or 연산자를 줄이고, 써야 한다면 적용 범위를 줄이십시오 • 캡처하지 않는 그룹을 사용하십시오 • 재사용할 텍스트를 캡처해서 후처리를 줄이십시오 • 필수적인 토큰을 드러내십시오 • “괴물같은 정규 표현식은 만들지 말자!!” 적합한 수량자를 쓰십시오 • 정규 표현식을 변수에 할당해서 재사용하십시오 • 복잡한 정규 표현식을 간단한 조각으로 나누십시오
  • 89. 정규식으르 쓰지 않는 것이 좋을 때 • 찾으려는 부분이 문자열의 어디에 위치하는지 미리 안다면 • 문자열 메서드만으로 처리 가능 하다면 endsWithSemicolon = /;$/.test(str); endsWithSemicolon = str.charAt(str.length - 1) == ";";
  • 90. 3 문자열 트리밍 • ECMAScript 5 : String.prototype.trim • 정규 표현식 최적화 예제 단골
  • 91. 정규식으로 트리밍 구현 // trim 1 if(!String.prototype.trim) { String.prototype.trim = function() { return this.replace(/^s+/, "").replace(/s+$/, ""); } } // 새 메서드를 테스트합니다. // 문자열 앞 공백에 탭(t) 문자와 줄바꿈(n) 문자를 넣었습니다. var str = " tn test string ".trim(); alert(str == "test string"); // "true"
  • 92. 정규식으로 트리밍 구현 // trim 2 String.prototype.trim = function() { return this.replace(/^s+|s+$/g, ""); } • or 연산자의 두 옵션을 문자열의 모든 위치에서 시도
  • 93. 정규식으로 트리밍 구현 // trim 3 String.prototype.trim = function() { return this.replace(/^s*([sS]*?)s*$/, "$1"); } • 게으른 수량자(*?) 때문에 필요 없는 역추적이 많이 발생
  • 94. 정규식으로 트리밍 구현 // trim 4 String.prototype.trim = function() { return this.replace(/^s*([sS]*S)?s*$/, "$1"); } • 탐욕적 수량자로 변경해도 성능 향상 • 모든 문자에 일치하는 클래스를 탐욕적 수량자로 반복할 경 우 특별한 최적화 (FF, Opera 9 제외)
  • 95. 정규식으로 트리밍 구현 // trim 5 String.prototype.trim = function() { return this.replace(/^s*(S*(s+S+)*)s*$/, "$1"); } • 지금까지 예시 중 가장 느림 • 내부 그룹이 한번에 한 단어씩 수량자 중첩 상태
  • 96. 정규식 없이 트리밍 구현 // trim 6 String.prototype.trim = function() { var start = 0, end = this.length - 1, ws = " nrtfx0bxa0u1680u180eu2000u2001u2002 u2003u2003u2004u2005u2006u2007u2008u2009 u200au200bu2028u2029u202fu205fu3000ufeff"; while(ws.indexOf(this.charAt(start)) > -1) { start++; } while(end > start && ws.indexOf(this.charAt(end)) > -1) { end--; } return this.slice(start, end + 1); }
  • 97. 정규식 없이 트리밍 구현 • 정규식은 중간에 문자를 고려하지 않고 맨 뒤 로 건너뛸 수 없음 • 이 경우 두 번째 while 문이 문자열 맨 뒤에서 시작 • 앞뒤 공백의 길이가 길면 성능 저하
  • 98. 장점만 취한 해결책 // trim 7 String.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); }
  • 100. 결과
  • 101. 4 요약 • 문자열을 매우 많이 합치거나 큰 문자열을 합칠 때 인터넷 익스플로러 7과 이전 버전에서 무난한 성능을 내 려면 배열 병합이 유일한 방법입니다. • 인터넷 익스플로러 7과 이전 버전을 지원할 필요가 없다면 문자열을 합치는 방법 중 가장 느린 배열 병합을 쓸 필요는 없습니다. 단순한 + 연산자와 += 연산자를 쓰고 불필요한 중간 단계의 문자열을 없애십시오. • 역추적은 정규 표현식의 기본적인 구성 요소지만 비효율의 원인이 될 때가 잦습니다. • 보통은 일치하는 것을 빠르게 찾아냈을 정규 표현식도 역추적이 폭주하면 느리게 동작하며 부분적으로 일 치하는 문자열에 적용했을 때는 브라우저를 멈추게 할 수 있습니다. 인접한 토큰을 상호배타적으로 만들고, 중첩된 수량자가 같은 부분에 일치하지 않게 만들고, 룩어헤드를 최소 그룹처럼 동작하게 해서 불필요한 역 추적을 없애면 이런 문제를 피할 수 있습니다. • 일치하는 부분을 빨리 찾을 수 있게 만들고 일치하지 않는 부분에서 시간을 덜 소비하게 하는 방법이 여러 가지 있습니다 (“정규 표현식의 효율성을 올리는 더 많은 방법”을 보십시오). • 정규 표현식이 항상 최선의 수단인 것은 아니며 특히 리터럴 문자열을 찾으려 할 때는 정규 표현식을 쓰지 않아도 됩니다. • 여러 가지 방법으로 문자열의 앞뒤 공백을 잘라낼 수 있지만 두 개의 단순한 정규 표현식을 써서 하나는 문 자열 앞의 공백문자를 제거하고 다른 하나는 문자열 뒤의 공백문자를 잘라내도록 하면 간결한 코드로도 문 자열의 길이나 구성에 구애받지 않고 다양한 브라우저에서 효율적이게 할 수 있습니다. 반복문을 써서 문자 열의 맨 뒤에서부터 공백 아닌 마지막 문자까지 거슬러 올라가게 하거나 이 방법을 정규 표현식과 결합하면 문자열의 전체 길이에 별 영향을 받지 않습니다.
  • 102. 4 요약 • 문자열을 매우 많이 합치거나 큰 문자열을 합칠 때 인터넷 익스플로러 7과 이전 버전에서 무난한 성능을 내 려면 배열 병합이 유일한 방법입니다. • 인터넷 익스플로러 7과 이전 버전을 지원할 필요가 없다면 문자열을 합치는 방법 중 가장 느린 배열 병합을 쓸 필요는 없습니다. 단순한 + 연산자와 += 연산자를 쓰고 불필요한 중간 단계의 문자열을 없애십시오. • 역추적은 정규 표현식의 기본적인 구성 요소지만 비효율의 원인이 될 때가 잦습니다. • 보통은 일치하는 것을 빠르게 찾아냈을 정규 표현식도 역추적이 폭주하면 느리게 동작하며 부분적으로 일 치하는 문자열에 적용했을 때는 브라우저를 멈추게 할 수 있습니다. 인접한 토큰을 상호배타적으로 만들고, 중첩된 수량자가 같은 부분에 일치하지 않게 만들고, 룩어헤드를 최소 그룹처럼 동작하게 해서 불필요한 역 추적을 없애면 이런 문제를 피할 수 있습니다. • 일치하는 부분을 빨리 찾을 수 있게 만들고 일치하지 않는 부분에서 시간을 덜 소비하게 하는 방법이 여러 가지 있습니다 (“정규 표현식의 효율성을 올리는 더 많은 방법”을 보십시오). • 정규 표현식이 항상 최선의 수단인 것은 아니며 특히 리터럴 문자열을 찾으려 할 때는 정규 표현식을 쓰지 않아도 됩니다. • 여러 가지 방법으로 문자열의 앞뒤 공백을 잘라낼 수 있지만 두 개의 단순한 정규 표현식을 써서 하나는 문 자열 앞의 공백문자를 제거하고 다른 하나는 문자열 뒤의 공백문자를 잘라내도록 하면 간결한 코드로도 문 자열의 길이나 구성에 구애받지 않고 다양한 브라우저에서 효율적이게 할 수 있습니다. 반복문을 써서 문자 열의 맨 뒤에서부터 공백 아닌 마지막 문자까지 거슬러 올라가게 하거나 이 방법을 정규 표현식과 결합하면 문자열의 전체 길이에 별 영향을 받지 않습니다.
  • 103. 주관적인 요약 • 모던 브라우저는 충분히 빠르다. (즉, 하위 브 라우저에서 효율성 테스트면 충분할지도) • 정규 표현식 동작 과정과 역추적 정도는 알고 있어야 한다. • 정규 표현식이 최선의 수단은 아니다.