Calcex Javascript Regex per personaggi accentati (segni diacritici)


166

Ho esaminato Stack Overflow ( sostituendo i caratteri ... eh , come JavaScript non segue lo standard Unicode relativo a RegExp , ecc.) E non ho davvero trovato una risposta concreta alla domanda:

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

Sto forzando un campo in un'interfaccia utente per abbinare il formato: last_name, first_name (ultimo [spazio virgola] prima) , e voglio fornire supporto per i segni diacritici, ma evidentemente in JavaScript è un po 'più difficile di altre lingue / piattaforme.

Questa era la mia versione originale, fino a quando non ho voluto aggiungere il supporto diacritico:

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

Attualmente sto discutendo di uno dei tre metodi per aggiungere supporto, tutti testati e funzionanti (almeno in una certa misura, non so davvero quale sia la "misura" del secondo approccio). Eccoli:

Elenco esplicito di tutti i personaggi accentati che vorrei accettare come validi (zoppi e eccessivamente complicati):


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àèìòùÀÈÌÒÙáéíóúýÁÉÍÓÚÝâêîôûÂÊÎÔÛãñõÃÑÕäëïöüÿÄËÏÖÜŸçÇßØøÅåÆæœ]+$/
  • Ciò corrisponde correttamente a un cognome / nome con uno dei caratteri accentati supportati in accentedCharacters.

Il mio altro approccio era usare la .classe di caratteri, per avere un'espressione più semplice:

var regex = /^.+,\s.+$/;
  • Questo sarebbe partita per qualsiasi cosa, almeno sotto forma di: something, something. Va bene, suppongo ...

L'ultimo approccio, che ho appena trovato, potrebbe essere più semplice ...

/^[a-zA-Z\u00C0-\u017F]+,\s[a-zA-Z\u00C0-\u017F]+$/
  • Corrisponde a una serie di personaggi unicode - testati e funzionanti, anche se non ho provato nulla di folle, solo le cose normali che vedo nel nostro dipartimento linguistico per i nomi dei membri della facoltà.

Ecco le mie preoccupazioni:

  1. La prima soluzione è troppo limitante, sciatta e contorta in questo. Dovrebbe essere cambiato se dimenticassi un personaggio o due, e questo non è molto pratico.
  2. La seconda soluzione è migliore, concisa, ma probabilmente corrisponde molto più di quanto dovrebbe effettivamente. Non sono riuscito a trovare una vera documentazione su esattamente ciò che .corrisponde, solo la generalizzazione di "qualsiasi carattere tranne il carattere di nuova riga" (da una tabella sulla MDN ).
  3. La terza soluzione sembra essere la più precisa, ma ci sono dei problemi? Non ho molta familiarità con Unicode, almeno in pratica, ma guardando una tabella di codici / continuazione di quella tabella , \u00C0-\u017Fsembra essere abbastanza solido, almeno per il mio input previsto.

    • La facoltà non invierà moduli con i loro nomi nella loro lingua madre (ad esempio, arabo, cinese, giapponese, ecc.), Quindi non devo preoccuparmi di caratteri fuori dal latino

Quindi le vere domande : quale di questi tre approcci è più adatto al compito? O ci sono soluzioni migliori?


1
Non sembra esserci alcun motivo particolare per usare le regexps più complicate. L'unica cosa della soluzione più semplice è che corrisponderà anche a "qualcosa, qualcosa, qualcosa". Potresti usare qualcosa del genere regex = /^[^,]+,\s[^,]+$/;per impedirlo.
usr2564301,

4
A prima vista, il primo non corrisponderà al nome comune "O'Donnell, Chris" né ai cognomi composti con un trattino, né a più cognomi (ecc.). Vedi i programmatori di Falsehoods credono sui nomi per quasi tutte le possibili insidie.
usr2564301,

" l' .atomo corrisponde a tutto tranne che alle nuove linee " in realtà è abbastanza esatto :-)
Bergi

1
Se è possibile utilizzare una libreria aggiuntiva, puoi dare un'occhiata alla mia risposta qui
stema

Jongware, in realtà ho appena letto quell'articolo mentre stavo sfogliando SO per una risposta alla mia domanda - Mi sono anche completamente dimenticato di trattini, apostrofi e simili, ero più interessato a renderlo internazionale prima: P Sono contento che tu l'abbia portato su però! E Stema, in realtà ho guardato quella libreria ed evito di incorporare le librerie perché questo è tutto su Google Apps Script: incorporare librerie esterne sarebbe un incubo e lo userei solo (in questo caso) per un campo particolare ... tipo di overkill: P
Chris Cirefice,

Risposte:


275

Il modo più semplice per accettare tutti gli accenti è questo:

[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 [ ] ^ \ × ÷

Vedi https://unicode-table.com/en/ per i caratteri elencati in ordine numerico.


2
Funziona bene, +1, ma potresti capire perché funziona?
Pierre Henry,

1
@PierreHenry the -definisce un intervallo, e questa tecnica sfrutta l'ordinamento dei caratteri nel set di caratteri per definire un intervallo continuo, creando una soluzione super concisa al problema
Angad,

8
questa corrispondenza non evidenzia (e gli altri caratteri non di parole tra Ze a)?
jcuenod,

21
Questo corrisponde almeno ai caratteri [,], ^ e \, nessuno dei quali dovrebbe essere incluso.
Nate,

2
Non funzionanti, pochi personaggi in questo intervallo non sono caratteri accentati (ad esempio U + 00D7 è il segno della moltiplicazione). Vedere questo: unicode-table.com/en
Jérémy Pouyet,

39

La gamma latina accentata \u00C0-\u017Fnon era abbastanza per il mio database di nomi, quindi ho esteso la regex a

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

Ho aggiunto questi blocchi di codice ( \u00C0-\u024Finclude tre blocchi adiacenti contemporaneamente):

Si noti che in \u00C0-\u00FFrealtà è solo una parte del Supplemento Latin-1 . Quell'intervallo salta i segnali di controllo non stampabili e tutti i simboli, tranne quelli posizionati in modo scomodo, moltiplicano × \u00D7e dividono ÷ \u00F7.

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

Se hai bisogno di più punti di codice, puoi trovare più intervalli nell'elenco di caratteri Unicode di Wikipedia . Ad esempio, potresti anche aggiungere Latin Extended-C , D ed E , ma li ho lasciati fuori perché ora solo gli storici sembrano interessati a loro e i set D ed E non vengono nemmeno visualizzati correttamente nel mio browser.

Il regex originale si fermò a \u017Fborked sul nome "olenol". Secondo Unicode Analyzer di FontSpace , quel primo personaggio è \u0218, LETTERA MAIUSCOLA S CON COMMA SOTTO. (Sì, di solito è scritto con una cedilla-S \u015E, "Enol". Ma non sto volando in Turchia per andare a dirgli: "Stai scrivendo il tuo nome sbagliato!")


1
Dando un'occhiata al blocco latino della tabella unicode , penso che dovresti includere anche \ u1e00- \ u1eff, quindi lo sto facendo[a-zA-Z\u00c0-\u024f\u1e00-\u1eff]
cprcrack

18

Quale di questi tre approcci è più adatto per l'attività?

Dipende dal compito :-) Per abbinare esattamente tutti i caratteri latini e le loro versioni accentate, le gamme Unicode probabilmente forniscono la soluzione migliore. Potrebbero essere estesi a tutti i caratteri non bianchi, cosa che potrebbe essere fatta usando la \Sclasse di caratteri.

Sto forzando un campo in un'interfaccia utente per abbinare il formato: last_name, first_name(ultimo [spazio virgola] prima)

Il problema di base che sto vedendo qui non sono i segni diacritici, ma gli spazi bianchi. Esistono alcuni nomi composti da più parole, ad esempio per i titoli. Quindi dovresti andare con il più generico, che consente tutto tranne la virgola che distingue per prima dal cognome:

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

Ma la tua seconda soluzione con la .classe di personaggi va bene, potresti aver bisogno solo di preoccuparti di più commate allora.


Forse hai ragione. Probabilmente ho complicato troppo ... Potresti spiegare la regex che hai fornito? Ho lavorato con regex per un po 'di tempo, ma solo roba di base, e davvero non ho idea di cosa faccia realmente il tuo! Ha
Chris Cirefice,

È una classe di caratteri negata - che significa "qualsiasi cosa oltre la virgola".
Bergi,

Ah, quindi sembra più simile any_character_not_a_comma, any_character_not_a_comma? Questo è quello che ho pensato quando l'ho letto per la prima volta, mi sono confuso quando ho visto tre virgole lì dentro.
Chris Cirefice,

Si, esattamente. Scusate la confusione con i dispersi sper lo spazio bianco ...
Bergi,

1
@ MateoTibaquirá Puoi semplificare [^\s]a\S
Bergi il

15

La libreria XRegExp ha un plugin chiamato Unicode che aiuta a risolvere compiti come questo.

<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>

È menzionato nei commenti alla domanda, ma è facile non vederlo. L'ho notato solo dopo aver inviato questa risposta.


Bello, risulta che in realtà non avevo bisogno di regex su Unicode, ma piuttosto sul modello anything, anything. Questo sarà utile per i futuri lettori :)
Chris Cirefice,

12

Cosa ne pensi di questo?

/^[a-zA-ZÀ-ÖØ-öø-ÿ]+$/

2
Non corrisponde Šš.
Gajus,

5

Che dire di questo?

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

Abbinerà ogni parola a caratteri accentati o meno.


2
Ma OP vuole consentire personaggi accentati.
Barbsan,


3
/^[\pL\pM\p{Zs}.-]+$/u

Spiegazione:

  • \pL - corrisponde a qualsiasi tipo di lettera da qualsiasi lingua
  • \pM - attacca un personaggio destinato ad essere combinato con un altro personaggio (es. accenti, dieresi, scatole allegate, ecc.)
  • \p{Zs} - corrisponde a un carattere di spazio bianco che è invisibile, ma occupa spazio
  • u - Le stringhe di motivi e soggetti sono trattate come UTF-8

A differenza di altri regex proposti (come [A-Za-zÀ-ÖØ-öø-ÿ]), questo funzionerà con tutti i caratteri specifici della lingua, ad esempio Ššè abbinato a questa regola, ma non abbinato da altri in questa pagina.

Sfortunatamente, JavaScript nativamente non supporta queste classi. Tuttavia, è possibile utilizzare xregexp, ad es

const XRegExp = require('xregexp');

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.