2016-08-25 3 views
13

Betrachten Sie die folgende Unicode-schweren regulären Ausdruck (Emojis in Vertretung von Nicht-ASCII und extra BMP Zeichen):Abfolge logischer OR in ES6/Unicode regulären Ausdruck in Chrome ✗ vs Firefox ✓

''.match(/||/ug) 

Firefox gibt [ "", "", "", "", "", "" ] zurück.

Chrome 52.0.2743.116 und Knoten 6.4.0 beide zurück null! Es scheint nicht zu kümmern, wenn ich die Zeichenfolge in eine Variable setzen und tun str.match(…), noch wenn ich ein RegExp-Objekt über new RegExp('||', 'gu') erstellen.

(Chrome ist ok mit nur ORing zwei Sequenzen: ''.match(/|/ug) ok Es ist auch in Ordnung, mit Nicht-Unicode. 'aakkzzkkaa'.match(/aa|kk|zz/ug) funktioniert.)

Mache ich etwas falsch? Ist das ein Chrome-Bug? Die ECMAScript compatibility table sagt, dass ich mit Unicode-Regexps in Ordnung sein sollte.

(PS:..? Die drei Emoji in diesem Beispiel verwendet werden nur Doubles In meiner Anwendung, werden sie willkürlich, aber deutliche Strings sein Aber ich frage mich, ob die Tatsache, dass ''.match(/[]/ug) Werke in Chrome relevant sind)

+0

Vielleicht nur konservativ ich bin, aber das wäre einfacher zu lesen 'foo',' bar' und 'baz' oder' A', 'B' und' C'. Außerdem machen viele Schriftarten immer noch nicht alle Emojis. Wenn also jemand zwei von ihnen vermisst, werden sie beide als ein Quadrat sehen - oder schlimmer noch, alle drei. –

+0

@CaptainMan die Welt spricht viele Sprachen, von denen viele mit Nicht-ASCII- oder (keuch!) Extra-BMP-Zeichen geschrieben sind. Ich verwende Emoji als Stehplatz für diese Charaktere. (Ich gebe auch in der Post an, dass das gleiche Beispiel mit ASCII arbeitet, also ist es ein Unicode-Problem.) Aktualisiere Titel, um Unicode zu betonen. –

+0

Ich sehe jetzt Teil des Punktes war für Unicode (verpasste es zuerst). Ich denke immer noch, dass mehr "Vanille" Unicode-Charaktere besser wären als Emojis. –

Antwort

3

Ohne die u Flag funktioniert Ihre Regexp, und das ist kein Wunder, da im BMP (= kein "u") Modus 16-Bit "Einheiten" zu 16-Bit "Einheiten", das heißt, ein Ersatz vergleicht zu einem anderen Ersatzpaar paaren.

Das Verhalten in der „u“ -Modus (die Codepoints vergleichen soll und nicht Einheiten) sieht in der Tat wie ein Chrome Bug, in der Zwischenzeit Sie jede Alternative in einer Gruppe einschließen kann, das gut zu funktionieren scheint:

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

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

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

Und hier ein kurzer Beweis dafür, dass mehr als zwei SMP Alternativen im u Modus aufgebrochen werden:

// insert a whatever range 
 
// from https://en.wikipedia.org/wiki/Plane_(Unicode)#Supplementary_Multilingual_Plane 
 
var range = '11300-1137F'; 
 

 
range = range.split('-').map(x => parseInt(x, 16)) 
 

 
var chars = []; 
 
for (var i = range[0]; i <= range[1]; i++) { 
 
    chars.push(String.fromCodePoint(i)) 
 
} 
 

 
var str = chars.join(''); 
 

 
while(chars.length) { 
 
    var re = new RegExp(chars.join('|'), 'u') 
 
    if(str.match(re)) 
 
     console.log(chars.length, re); 
 
    chars.pop(); 
 
}

in Chrom, protokolliert er nur die letzten beiden Regexes (2 und 1 Alts).

2

ohne "u" -Flagge es auch

für mich in Chrom (52.0.2743.116) funktioniert scheint

gut u -Kennzeichen

gebrochen werden, es sei denn Sie Multiplikator verwenden ''.match(/|{2}|/g) -> null {1} und {1,} scheinen zu arbeiten, ich nehme an, dass sie übersetzt werden? und +. Ich nehme an, ohne das "u" -Flag {2} wird als \ud83c\udf66{2} interpretiert, was das Verhalten erklären würde.

gerade mit (?:){2} getestet scheint dies richtig zu funktionieren. Ich denke, das bestätigt meine Annahme über den Multiplikator.

hier eine schnelle Lösung dafür:

//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's 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, kam nicht mit einer besseren Funktionsnamen bis