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) == ";";
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);
}
101. 4 요약
• 문자열을 매우 많이 합치거나 큰 문자열을 합칠 때 인터넷 익스플로러 7과 이전 버전에서 무난한 성능을 내
려면 배열 병합이 유일한 방법입니다.
• 인터넷 익스플로러 7과 이전 버전을 지원할 필요가 없다면 문자열을 합치는 방법 중 가장 느린 배열 병합을
쓸 필요는 없습니다. 단순한 + 연산자와 += 연산자를 쓰고 불필요한 중간 단계의 문자열을 없애십시오.
• 역추적은 정규 표현식의 기본적인 구성 요소지만 비효율의 원인이 될 때가 잦습니다.
• 보통은 일치하는 것을 빠르게 찾아냈을 정규 표현식도 역추적이 폭주하면 느리게 동작하며 부분적으로 일
치하는 문자열에 적용했을 때는 브라우저를 멈추게 할 수 있습니다. 인접한 토큰을 상호배타적으로 만들고,
중첩된 수량자가 같은 부분에 일치하지 않게 만들고, 룩어헤드를 최소 그룹처럼 동작하게 해서 불필요한 역
추적을 없애면 이런 문제를 피할 수 있습니다.
• 일치하는 부분을 빨리 찾을 수 있게 만들고 일치하지 않는 부분에서 시간을 덜 소비하게 하는 방법이 여러
가지 있습니다 (“정규 표현식의 효율성을 올리는 더 많은 방법”을 보십시오).
• 정규 표현식이 항상 최선의 수단인 것은 아니며 특히 리터럴 문자열을 찾으려 할 때는 정규 표현식을 쓰지
않아도 됩니다.
• 여러 가지 방법으로 문자열의 앞뒤 공백을 잘라낼 수 있지만 두 개의 단순한 정규 표현식을 써서 하나는 문
자열 앞의 공백문자를 제거하고 다른 하나는 문자열 뒤의 공백문자를 잘라내도록 하면 간결한 코드로도 문
자열의 길이나 구성에 구애받지 않고 다양한 브라우저에서 효율적이게 할 수 있습니다. 반복문을 써서 문자
열의 맨 뒤에서부터 공백 아닌 마지막 문자까지 거슬러 올라가게 하거나 이 방법을 정규 표현식과 결합하면
문자열의 전체 길이에 별 영향을 받지 않습니다.
102. 4 요약
• 문자열을 매우 많이 합치거나 큰 문자열을 합칠 때 인터넷 익스플로러 7과 이전 버전에서 무난한 성능을 내
려면 배열 병합이 유일한 방법입니다.
• 인터넷 익스플로러 7과 이전 버전을 지원할 필요가 없다면 문자열을 합치는 방법 중 가장 느린 배열 병합을
쓸 필요는 없습니다. 단순한 + 연산자와 += 연산자를 쓰고 불필요한 중간 단계의 문자열을 없애십시오.
• 역추적은 정규 표현식의 기본적인 구성 요소지만 비효율의 원인이 될 때가 잦습니다.
• 보통은 일치하는 것을 빠르게 찾아냈을 정규 표현식도 역추적이 폭주하면 느리게 동작하며 부분적으로 일
치하는 문자열에 적용했을 때는 브라우저를 멈추게 할 수 있습니다. 인접한 토큰을 상호배타적으로 만들고,
중첩된 수량자가 같은 부분에 일치하지 않게 만들고, 룩어헤드를 최소 그룹처럼 동작하게 해서 불필요한 역
추적을 없애면 이런 문제를 피할 수 있습니다.
• 일치하는 부분을 빨리 찾을 수 있게 만들고 일치하지 않는 부분에서 시간을 덜 소비하게 하는 방법이 여러
가지 있습니다 (“정규 표현식의 효율성을 올리는 더 많은 방법”을 보십시오).
• 정규 표현식이 항상 최선의 수단인 것은 아니며 특히 리터럴 문자열을 찾으려 할 때는 정규 표현식을 쓰지
않아도 됩니다.
• 여러 가지 방법으로 문자열의 앞뒤 공백을 잘라낼 수 있지만 두 개의 단순한 정규 표현식을 써서 하나는 문
자열 앞의 공백문자를 제거하고 다른 하나는 문자열 뒤의 공백문자를 잘라내도록 하면 간결한 코드로도 문
자열의 길이나 구성에 구애받지 않고 다양한 브라우저에서 효율적이게 할 수 있습니다. 반복문을 써서 문자
열의 맨 뒤에서부터 공백 아닌 마지막 문자까지 거슬러 올라가게 하거나 이 방법을 정규 표현식과 결합하면
문자열의 전체 길이에 별 영향을 받지 않습니다.
103. 주관적인 요약
• 모던 브라우저는 충분히 빠르다. (즉, 하위 브
라우저에서 효율성 테스트면 충분할지도)
• 정규 표현식 동작 과정과 역추적 정도는 알고
있어야 한다.
• 정규 표현식이 최선의 수단은 아니다.