Быстрый trim для JavaScript

Самый быстрый trim на JavaScript выглядит странно:

function trim12 (str) {
    var	str = str.replace(/^\s\s*/, ''),
        ws = /\s/,
        i = str.length;
    while (ws.test(str.charAt(--i)));
    return str.slice(0, i + 1);
}

Код взят из блога Flagrant Badassery. Цикл с регуляркой быстрее, чем простое регулярное выражение /\s+$/, а кроме того, \s\s* быстрее, чем \s+? OMG!

Комментарии 13

baka.name № 1

Регулярные выражения — это же не магия, а конечные автоматы. ^_^

Цикл с регуляркой быстрее, чем простое регулярное выражение /\s+$/

Это вполне понятно — цикл делает только то, что надо — сравнивает с «пробельным классом символов» по одному символы, начиная с конца строки, пока они есть.
А «простое регулярное выражение» начинает сопоставляться с каждого «пробельного» символа, начиная с начала строки, потом обламывается, не обнаружив конца строки после пробелов (если их было несколько подряд — то всё равно пытается проделать то же самое начиная со второго из них, и т.д…).

а кроме того, \s\s* быстрее, чем \s+

Это не столь очевидно, правда, напоминает фридловскую «развёртку регекспа», но сейчас не помню, почему она эффективнее.
(И не понимаю, почему оно эффективнее _здесь_. -_-')

Евгений Степанищев (bolknote.ru) автор № 4
Я понимаю, что это не магия. Но я ожидал от движков регулярных выражений в JS большей оптимизированности. \s\s* просто обнажает недостатки этих движков.
Азат Разетдинов (razetdinov.ya.ru) № 2
«Простое» регулярное выражение спотыкается на каждом пробеле, пока дойдёт до конца строки; приведённый код сразу идёт в конец и ищет пробелы перед ним.
Евгений Степанищев (bolknote.ru) автор № 3
Движки регулярок сильно оптимизируются. \s+$ вполне можно соптимизировать как «начать цикл с конца, если не пробел, остановиться». Я не смотрел в код, но даже не сомневаюсь, что libprce именно так и делает.
Евгений Степанищев (bolknote.ru) автор № 5
«Если не пробел» читать как «если не пробельный символ».
Азат Разетдинов (razetdinov.ya.ru) № 6
Комментарий для Евгения Степанищева:

http://pcre.org/pcre.txt
“Consider a simple pattern such as ‘abcd$’ when applied to a long string that does not match. Because matching proceeds from left to right, PCRE will look for each «a» in the subject and then see if what follows matches the rest of the pattern.”
realsonic.moikrug.ru № 8
У браузеров разные движки, вроде бы? Насколько я знаю, Firefox и Chrome используют какие-то новые разработки, компилируемый JS.
Евгений Степанищев (bolknote.ru) автор № 9
Разные, конечно. Но оптимизация regexp, видимо, находится в удручающем состоянии у всех.
Meettya (meettya.pip.verisignlabs.com) № 10
Суть проблемы в том, что для JavaScript строка одним куском — по сути join массива.
Соответственно — методы массива на большом массиве работают быстрее, чем литеральная его обработка после join.
Ведь str.charAt(--i)=str[--i]
Так и получается, когда «все есть объект».
Meettya (meettya.pip.verisignlabs.com) № 11
Т.е. смысл в том, что сама по себе задача решается для «сферического коня в вакууме».
Я на стопяцот процентов уверен, что «откуси» он достаточный кусок СНАЧАЛА и с КОНЦА и обработай оба одной и той же регуляркой /^\s+|\s+$/ а потом слепи он это обратно — будет не медленнее его конечного варианта. Но так же извратно по сути. :)