Подтвердить что ты не робот

Последовательность логического ИЛИ в регулярном выражении ES6/Unicode в Chrome ✗ против Firefox ✓

Рассмотрим следующее регулярное выражение Unicode-тяжелое (emoji, стоящий для символов, отличных от ASCII и вне BMP):

'🍤🍦🍋🍋🍦🍤'.match(/🍤|🍦|🍋/ug)

Firefox возвращает [ "🍤", "🍦", "🍋", "🍋", "🍦", "🍤" ] 🤗.

Chrome 52.0.2743.116 и Node 6.4.0 оба возвращают null! Кажется, мне неинтересно, если я поместил строку в переменную и сделаю str.match(…), и если я создам объект RegExp через new RegExp('🍤|🍦|🍋', 'gu').

(Хром в порядке с просто ORing в двух последовательностях: '🍤🍦🍋🍋🍦🍤'.match(/🍤|🍦/ug) в порядке. Также он работает с не-Unicode: 'aakkzzkkaa'.match(/aa|kk|zz/ug) работает.)

Я что-то делаю неправильно? Это ошибка Chrome? Таблица совместимости ECMAScript говорит, что я должен быть в порядке с регулярными выражениями Unicode.

(PS: три emoji, используемые в этом примере, являются просто stand-ins. В моем приложении они являются произвольными, но разными строками. Но мне интересно, имеет ли значение тот факт, что '🍤🍦🍋🍋🍦🍤'.match(/[🍤🍦🍋]/ug) работает в Chrome?)

4b9b3361

Ответ 1

Без флага u ваше регулярное выражение работает, и это неудивительно, поскольку в режиме BMP (= нет "u" ) он сравнивает 16-разрядные "единицы" с 16-разрядными "единицами", то есть, суррогатная пара с другой суррогатной парой.

Поведение в режиме "u" (которое должно сравниться с кодовыми точками, а не единицами) выглядит действительно как ошибка Chrome, тем временем вы можете заключить каждую альтернативу в группу, которая, кажется, работает нормально:

m = '🍤🍦🍋🍋🍦🍤'.match(/(🍤)|(🍦)|(🍋)/ug)
console.log(m)

// note that the groups must be capturing!
// this doesn't work:

m = '🍤🍦🍋🍋🍦🍤'.match(/(?:🍤)|(?:🍦)|(?:🍋)/ug)
console.log(m)

Ответ 2

без "u" -flag он также работает в chrome (52.0.2743.116) для меня

Значок u -flag кажется сломанным

если вы не используете множитель '🍤🍤🍦🍦🍦🍦🍋🍋🍋🍋🍦🍦🍦🍦🍤🍤'.match(/🍤|🍦{2}|🍋/g) → null {1} и {1,}, похоже, работают, я предполагаю, что они переведены на? и+. Я предполагаю, что без "u" -flag 🍦{2} интерпретируется как \ud83c\udf66{2}, что объясняет поведение.

только что протестированный с помощью (?:🍦){2}, похоже, работает правильно. Думаю, это подтверждает мое предположение о множителе.

здесь быстрое решение для этого:

//a utility I usually have in my codes
var replace = (pattern, replacement) => value => String(value).replace(pattern, replacement);

var fixRegexSource = replace(
    /[\ud800-\udbff][\udc00-\udfff]/g, 
    //"(?:$&)" //not sure wether this might still be buggy
    //that why I convert it into the unicode-syntax,
    //this can't be misinterpreted
    c => `(?:\\u${c.charCodeAt(0).toString(16)}\\u${c.charCodeAt(1).toString(16)})`
);

var fixRegex = regex => new RegExp(
    fixRegexSource(regex.source), 
    regex.flags.replace("u", "")
);

sry, не придумали лучшие имена функций