Последовательность логического ИЛИ в регулярном выражении 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?)
Ответы
Ответ 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, не придумали лучшие имена функций