Konkreter Javascript Regex für Akzentzeichen (Diakritika)

165

Ich habe auf Stack - Überlauf (sehe ersetzen Zeichen .. eh , wie JavaScript , um den Unicode - Standard über RegExp nicht folgen , etc.) und hat nicht wirklich eine konkrete Antwort auf die Frage gefunden:

How can JavaScript match for accented characters (those with diacritical marks)?

Ich zwinge ein Feld in einer Benutzeroberfläche dazu, dem Format zu entsprechen: last_name, first_name (letztes [Komma] zuerst) , und ich möchte diakritische Zeichen unterstützen, aber in JavaScript ist es offensichtlich etwas schwieriger als in anderen Sprachen / Plattformen.

Dies war meine ursprüngliche Version, bis ich diakritische Unterstützung hinzufügen wollte:

/^[a-zA-Z]+,\s[a-zA-Z]+$/

Derzeit diskutiere ich über eine von drei Methoden, um Unterstützung hinzuzufügen, die ich alle getestet habe und arbeite (zumindest bis zu einem gewissen Grad weiß ich nicht wirklich, wie groß der zweite Ansatz ist). Hier sind sie:

Explizite Auflistung aller Zeichen mit Akzent, die ich als gültig akzeptieren möchte (lahm und übermäßig kompliziert):


var accentedCharacters = "àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇßØøÅåÆæœ";
// Build the full regex
var regex = "^[a-zA-Z" + accentedCharacters + "]+,\\s[a-zA-Z" + accentedCharacters + "]+$";
// Create a RegExp from the string version
regexCompiled = new RegExp(regex);
// regexCompiled = /^[a-zA-ZàèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇßØøÅåÆæœ]+,\s[a-zA-ZàèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇßØøÅåÆæœ]+$/
  • Dies stimmt korrekt mit einem Nach- / Vornamen mit einem der unterstützten Zeichen mit Akzent in überein accentedCharacters.

Mein anderer Ansatz war, die .Zeichenklasse zu verwenden , um einen einfacheren Ausdruck zu haben:

var regex = /^.+,\s.+$/;
  • Dies würde für fast alles passen, zumindest in Form von : something, something. Das ist in Ordnung, nehme ich an ...

Der letzte Ansatz, den ich gerade gefunden habe, könnte einfacher sein ...

/^[a-zA-Z\u00C0-\u017F]+,\s[a-zA-Z\u00C0-\u017F]+$/
  • Es passt zu einer Reihe von Unicode-Zeichen - getestet und funktioniert, obwohl ich nichts Verrücktes ausprobiert habe, nur das normale Zeug, das ich in unserer Sprachabteilung für Namen von Fakultätsmitgliedern sehe.

Hier sind meine Bedenken:

  1. Die erste Lösung ist viel zu einschränkend und schlampig und verworren. Es müsste geändert werden, wenn ich ein oder zwei Charaktere vergessen hätte, und das ist einfach nicht sehr praktisch.
  2. Die zweite Lösung ist besser, prägnant, passt aber wahrscheinlich weit mehr als sie eigentlich sollte. Ich konnte keine wirkliche Dokumentation darüber finden , was genau. übereinstimmt, nur die Verallgemeinerung von "irgendeinem Zeichen außer dem Zeilenumbruchzeichen" (aus einer Tabelle im MDN ).
  3. Die dritte Lösung scheint die genaueste zu sein, aber gibt es Fallstricke? Ich bin nicht sehr vertraut mit Unicode, zumindest in der Praxis, aber bei einer Suche Code - Tabelle / Fortsetzung der Tabelle , \u00C0-\u017Fscheint ziemlich fest zu sein, zumindest für meine erwartete Eingabe.

    • Die Fakultät wird keine Formulare mit ihren Namen in ihrer Muttersprache (z. B. Arabisch, Chinesisch, Japanisch usw.) einreichen, sodass ich mich nicht um Zeichen mit nicht lateinischem Zeichensatz kümmern muss

Die eigentliche Frage (n) : Welcher dieser drei Ansätze eignet sich am besten für die Aufgabe? Oder gibt es bessere Lösungen?

Chris Cirefice
quelle
1
Es scheint keinen besonderen Grund zu geben, die komplizierteren regulären Ausdrücke zu verwenden. Das Einzige an der einfachsten Lösung ist, dass sie auch zu "etwas, etwas, etwas" passt. Sie könnten so etwas verwenden regex = /^[^,]+,\s[^,]+$/;, um das zu verhindern.
usr2564301
4
Auf einen Blick entspricht der erste weder dem gebräuchlichen Namen "O'Donnell, Chris" noch den zusammengesetzten Nachnamen mit einem Bindestrich oder mehreren Nachnamen (usw.). Unter Falsehoods Programmers Believe About Names finden Sie nahezu alle möglichen Fallstricke.
usr2564301
" Das .Atom passt zu allem außer Zeilenumbrüchen " ist eigentlich ziemlich genau :-)
Bergi
1
Wenn es Ihnen möglich ist, eine zusätzliche Bibliothek zu verwenden, können Sie sich meine Antwort hier
ansehen
Jongware, ich habe diesen Artikel gerade gelesen, als ich SO nach einer Antwort auf meine Frage suchte. Ich habe auch Bindestriche und Apostrophe und dergleichen völlig vergessen. Ich war mehr darum bemüht, ihn zuerst international zu machen: P Ich bin froh, dass Sie ihn mitgebracht haben aber auf! Und Stema, ich habe mir diese Bibliothek tatsächlich angesehen und vermeide das Einbinden von Bibliotheken, da dies alles in Google Apps Script enthalten ist. Das Einbinden externer Bibliotheken wäre ein Albtraum, und ich würde es (in diesem Fall) nur für ein bestimmtes Feld verwenden ... Art von Overkill: P
Chris Cirefice

Antworten:

273

Der einfachere Weg, alle Akzente zu akzeptieren, ist folgender:

[A-zÀ-ú] // accepts lowercase and uppercase characters
[A-zÀ-ÿ] // as above but including letters with an umlaut (includes [ ] ^ \ × ÷)
[A-Za-zÀ-ÿ] // as above but not including [ ] ^ \
[A-Za-zÀ-ÖØ-öø-ÿ] // as above but not including [ ] ^ \ × ÷

Unter https://unicode-table.com/en/ finden Sie Zeichen in numerischer Reihenfolge.

Maycow Moura
quelle
2
Es funktioniert gut, +1, aber können Sie erläutern, warum es funktioniert?
Pierre Henry
1
@PierreHenry -definiert einen Bereich, und diese Technik nutzt die Reihenfolge der Zeichen im Zeichensatz, um einen kontinuierlichen Bereich zu definieren, was zu einer sehr präzisen Lösung des Problems führt
Angad
8
Stimmt dies nicht mit Unterstrichen überein (und den anderen Nicht-Wort-Zeichen zwischen Zund a)?
Jcuenod
21
Dies entspricht mindestens den Zeichen [,], ^ und \, von denen keines enthalten sein sollte.
Nate
2
Funktioniert nicht, nur wenige Zeichen in diesem Bereich sind Zeichen ohne Akzent (U + 00D7 ist beispielsweise das Multiplikationszeichen). Siehe hierzu: unicode-table.com/de
Jérémy Pouyet
39

Der akzentuierte lateinische Bereich \u00C0-\u017Freichte für meine Datenbank mit Namen nicht aus, daher erweiterte ich den regulären Ausdruck auf

[a-zA-Z\u00C0-\u024F]
[a-zA-Z\u00C0-\u024F\u1E00-\u1EFF] // includes even more Latin chars

Ich habe diese Codeblöcke hinzugefügt ( \u00C0-\u024Fenthält drei benachbarte Blöcke gleichzeitig):

Beachten Sie, dass dies \u00C0-\u00FFeigentlich nur ein Teil des Latin-1-Supplements ist . Dieser Bereich überspringt nicht druckbare Steuersignale und alle Symbole mit Ausnahme der ungünstig platzierten Multiplikation × \u00D7und Division ÷ \u00F7.

[a-zA-Z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u024F] // exclude ×÷

Wenn Sie mehr Codepunkte benötigen, finden Sie weitere Bereiche in der Wikipedia- Liste der Unicode-Zeichen . Zum Beispiel könnten Sie auch Latin Extended-C , D und E hinzufügen , aber ich habe sie weggelassen, weil nur Historiker jetzt an ihnen interessiert zu sein scheinen und die D- und E-Sets in meinem Browser nicht einmal richtig gerendert werden.

Der ursprüngliche Regex, der bei \u017Fanhält, trägt den Namen "Șenol". Laut dem Unicode Analyzer von FontSpace lautet das erste Zeichen \u0218LATIN CAPITAL LETTER S WITH COMMA BELOW. (Ja, normalerweise wird es mit einem Cedilla-S geschrieben \u015E, "olenol". Aber ich fliege nicht in die Türkei, um ihm zu sagen: "Du schreibst deinen Namen falsch!")

Chaim Leib Halbert
quelle
1
Wenn Sie sich den lateinischen Block der Unicode-Tabelle ansehen, sollten Sie auch \ u1e00- \ u1eff einschließen, also mache ich[a-zA-Z\u00c0-\u024f\u1e00-\u1eff]
cprcrack
18

Welcher dieser drei Ansätze eignet sich am besten für die Aufgabe?

Abhängig von der Aufgabe :-) Um genau allen lateinischen Zeichen und ihren akzentuierten Versionen zu entsprechen, bieten die Unicode-Bereiche wahrscheinlich die beste Lösung. Sie können auf alle Nicht-Leerzeichen erweitert werden, was mit der \SZeichenklasse erfolgen kann.

Ich zwinge ein Feld in einer Benutzeroberfläche dazu, dem Format zu entsprechen: last_name, first_name(letztes [Komma] zuerst)

Das grundlegendste Problem, das ich hier sehe, sind keine Diakritika, sondern Leerzeichen. Es gibt einige Namen, die aus mehreren Wörtern bestehen, z. B. für Titel. Sie sollten sich also für das allgemeinste entscheiden, das alles außer dem Komma zulässt, das den Vor- und Nachnamen unterscheidet:

/[^,]+,\s[^,]+/

Aber Ihre zweite Lösung mit der .Zeichenklasse ist genauso gut, dass Sie sich dann möglicherweise nur um mehrere Kommas kümmern müssen.

Bergi
quelle
Hm, vielleicht hast du recht. Ich habe es wahrscheinlich zu kompliziert ... Könnten Sie den von Ihnen bereitgestellten regulären Ausdruck erklären? Ich arbeite jetzt schon eine Weile mit Regex, aber nur mit grundlegenden Dingen, und ich habe wirklich keine Ahnung, was deine tatsächlich tut! Ha
Chris Cirefice
Es ist eine negierte Zeichenklasse - was "alles außer dem Komma" bedeutet.
Bergi
Ah, so liest es sich eher any_character_not_a_comma, any_character_not_a_comma? Das dachte ich mir, als ich es zum ersten Mal las. Ich war etwas verwirrt, als ich dort drei Kommas sah.
Chris Cirefice
Ja genau. Entschuldigen Sie die Verwechslung mit dem fehlenden sLeerzeichen…
Bergi
1
@ MateoTibaquirá Sie können vereinfachen, [^\s]um\S
Bergi
15

Die XRegExp- Bibliothek verfügt über ein Plugin namens Unicode , mit dessen Hilfe solche Aufgaben gelöst werden können.

<script src="xregexp.js"></script>
<script src="addons/unicode/unicode-base.js"></script>
<script>
  var unicodeWord = XRegExp("^\\p{L}+$");

  unicodeWord.test("Русский"); // true
  unicodeWord.test("日本語"); // true
  unicodeWord.test("العربية"); // true
</script>

Es wird in den Kommentaren zur Frage erwähnt, ist aber leicht zu übersehen. Ich habe es erst bemerkt, nachdem ich diese Antwort eingereicht habe.

Dorn
quelle
Schön, es stellt sich heraus, dass ich nicht unbedingt auf Unicode, sondern auf das Muster neu ausdrücken musste anything, anything. Dies wird für zukünftige Leser nützlich sein :)
Chris Cirefice
12

Wie wäre es damit?

/^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/
alchn
quelle
2
Passt nicht zusammen Šš.
Gajus
5

Was ist damit?

^([a-zA-Z]|[à-ú]|[À-Ú])+$

Es wird jedes Wort mit akzentuierten Zeichen übereinstimmen oder nicht.

Javier Pallarés
quelle
2
Aber OP möchte Zeichen mit Akzent zulassen .
Barbansan
3
/^[\pL\pM\p{Zs}.-]+$/u

Erläuterung:

  • \pL - passt zu jeder Art von Brief aus jeder Sprache
  • \pM - greift ein Zeichen an, das mit einem anderen Zeichen kombiniert werden soll (z. B. Akzente, Umlaute, umschließende Kästchen usw.)
  • \p{Zs} - Entspricht einem Leerzeichen, das unsichtbar ist, aber Platz beansprucht
  • u - Muster- und Betreffzeichenfolgen werden als UTF-8 behandelt

Im Gegensatz zu anderen vorgeschlagenen regulären Ausdrücken (z. B. [A-Za-zÀ-ÖØ-öø-ÿ]) funktioniert dies mit allen sprachspezifischen Zeichen, z. B. Ššentspricht diese Regel, nicht jedoch anderen auf dieser Seite.

Leider unterstützt JavaScript diese Klassen von Haus aus nicht. Sie können jedoch xregexpz

const XRegExp = require('xregexp');

const isInputRealHumanName = (input: string): boolean => {
  return XRegExp('^[\\pL\\pM-]+ [\\pL\\pM-]+$', 'u').test(input);
};
Gajus
quelle