2014-06-22 23 views
5

ich mich für einige regex Code mit diesem Muster suchen:Spiel alpha Buchstaben und akzentuierte alpha Buchstaben

  • Muss mindestens 1 der folgenden und passen die gesamte Zeichenfolge enthalten.

  • Kann nur alpha Buchstaben (A-Z A-Z) enthalten, ...

  • und akzentuierten Buchstaben alpha (a a a usw.).

ich preg_match('/^([\p{L}]*)$/iu', $input) bin mit, aber \p{L} Matches alle Unicode-Zeichen, einschließlich Chinesisch. Ich möchte nur die Buchstaben des englischen Alphabets zulassen, aber auch die akzentuierten Varianten von ihnen.

So JohnDoe, Fübar, Lòrem, FírstNäme, Çákë würden alle gültigen Eingaben, weil sie alle mindestens 1 alpha Buchstaben und/oder akzentuierte alpha Buchstaben, und die gesamte Zeichenfolge Matches enthalten.

+0

Haben Sie Beispieleingabedaten zum Vergleich? – JakeGould

+0

[[: alpha:]] löst es nicht? –

+0

@AfonsoTsukamoto Probieren Sie es aus. Es passt immer noch chinesische und japanische Charaktere. – JakeGould

Antwort

0

Akzentuierte Alpha-Buchstaben sind Unicode-Zeichen, die völlig unabhängig von ihren unakzentuierten Varianten sind. Es kann von einem menschlichen Beobachter gesehen werden, aber ein Computer wird keine Möglichkeit haben, den Unterschied zu erkennen, indem er ihn mit Alpha-Zeichen des Standard-ASCII-Satzes vergleicht. Eine Möglichkeit, dies zu erreichen, besteht darin, dass Sie Ihrer Regexp eine Whitelist zur Verfügung stellen, deren Zeichen erlaubt sind. Falls Sie die Zeichen mit Akzent nicht benötigen, verwenden Sie eine Bibliothek wie Apache Lucene (eine Java-Bibliothek, aber ich glaube, ich kann sie in PHP verwenden) wird die Akzentbuchstaben für ihre unbetonten Varianten ersetzen mit dem/den richtigen Analysator/en.

+1

Nicht 100% richtig. Sie können vordefinierte Unicode-Skripts verwenden, um bestimmte Unicode-Zeichengruppen wie hier beschrieben zu finden. http://www.regular-expressions.info/unicode.html#category – JakeGould

+0

@JakeGould Schönes Ergebnis. Aber würde das nicht scheitern, wenn Sie das Eingabeformat nicht als Buchstabe + Zeichen sondern nur als Buchstaben erhalten? –

+0

Nicht 100% klar, was Sie meinen. Schau dir meine Antwort an, wo ich erkläre, was '\ p {Common}' genauso gut ist wie '\ p {Latin}'. Letztlich kann man nur in großen, vordefinierten Schwaden leicht vergleichen. Aber es gibt Möglichkeiten, die abhängig von der Nützlichkeit und den Bedürfnissen Ihres Skripts sind. – JakeGould

1

Mit den Beispieldaten sowie einigen chinesischen & japanischen Zeichen scheint die Regex /[!\p{Common}\p{Latin}]*/iu zu funktionieren. Für weitere Details, diese Seite hat einige schöne Hintergrundinformationen zu predefined Unicode categories sowie eine schöne simple explanation here. Aber es gibt eine leere Übereinstimmung für die nicht-lateinischen Zeichen in dieser Version zurück. Die in meinem EDIT: am Boden wird für saubere Boolesche Logik am besten:

// Set a test array. 
$test_array = array(); 
$test_array[] = 'JóhnDoe'; 
$test_array[] = 'Fübar'; 
$test_array[] = 'Lòrem'; 
$test_array[] = 'FírstNäme'; 
$test_array[] = '•••••••'; 
$test_array[] = 'Çákë'; 
$test_array[] = '形声字/形聲字'; 
$test_array[] = 'ラドクリフ、マラソン'; 

// Set the header for debugging output. 
header('Content-Type: text/plain; charset=utf-8'); 

// Roll through the test array. 
foreach ($test_array as $test_value) { 

    // Run a regex to detect latin and common characters. 
    preg_match('/[!\p{Common}\p{Latin}]*/iu', $test_value, $matches); 

    // Kludge using array filtering to get rid of empty matches. 
    $matches = array_filter($matches); 

    // Dump the matches for debugging. 
    print_r($matches); 

} 

Die Ausgabe ist wie folgt: Beachten Sie, wie die chinesischen & japanischen Schriftzeichen leer Streichhölzer zurück. Beachten Sie auch, wie die ••••••• dank der Regex-Übereinstimmung \p{Common} durchkommt. Wenn Sie nicht wollen, dass gewöhnliche Zeichen wie diese durchkommen, ändern Sie einfach die Regex, /[!\p{Latin}]*/iu. Ich verwende array_filter, um diese leeren Werte zu bereinigen, aber es ist kludgy. Das ist also nicht perfekt, aber brauchbar:

Array 
(
    [0] => JóhnDoe 
) 
Array 
(
    [0] => Fübar 
) 
Array 
(
    [0] => Lòrem 
) 
Array 
(
    [0] => FírstNäme 
) 
Array 
(
    [0] => ••••••• 
) 
Array 
(
    [0] => Çákë 
) 
Array 
(
) 
Array 
(
) 

EDIT: Dieser Test Code verwendet eine Variante des regex ich oben geschrieben die leere Nicht-Spiel Ausgabe oben zu beseitigen; /(?:[\p{Latin}])+/iu. Beachten Sie, dass dies nur durch Abgleich mit \p{Latin} funktioniert, so dass \p{Common} hier nicht gut wiedergegeben werden kann. Aber die Ergebnisse /(?:[\p{Latin}])+/iu mit sauberen und versichern Sie eine einfache boolean Prüfung von preg_match verwenden können für Zeichen zu überprüfen, anstatt eine Flickschusterei zu verwenden, zu haben, die mischt die $matches Array mit array_filter:

// Set a test array. 
$test_array = array(); 
$test_array[] = 'JóhnDoe'; 
$test_array[] = 'Fübar'; 
$test_array[] = 'Lòrem'; 
$test_array[] = 'FírstNäme'; 
$test_array[] = '•••••••'; 
$test_array[] = 'Çákë'; 
$test_array[] = '形声字/形聲字'; 
$test_array[] = 'ラドクリフ、マラソン'; 

// Set the header for debugging output. 
header('Content-Type: text/plain; charset=utf-8'); 

// Roll through the test array. 
foreach ($test_array as $test_value) { 

    // Run a regex to detect latin and common characters. 
    preg_match('/(?:[\p{Latin}])+/iu', $test_value, $matches); 

    // Dump the matches for debugging. 
    print_r($matches); 

} 

Und die neuen Ergebnisse sind wie folgt.Beachten Sie, dass die leeren Felder wirklich leer sind und die prey_match ein boolean false in diesen Fällen zurück:

Array 
(
    [0] => JóhnDoe 
) 
Array 
(
    [0] => Fübar 
) 
Array 
(
    [0] => Lòrem 
) 
Array 
(
    [0] => FírstNäme 
) 
Array 
(
) 
Array 
(
    [0] => Çákë 
) 
Array 
(
) 
Array 
(
) 
+0

nach dem Lesen später geschrieben zx81 Antwort, ich denke, es verdient in dieser Frage top. Seine kompakte elegante Regexp mit meinem Update wird jetzt in PCRE, JavaScript und Python funktionieren, kann es wirklich für jemand anderen nützlich sein –

+1

@JuanGarcia Fine. Dies ist kein Wettbewerb. Er funktioniert besser, weil er keine ungeraden leeren Sätze zurückgibt, wie es meine Regex tut. Dafür gebe ich nur +1. Aber die Tatsache, dass meine in JavaScript nicht funktioniert, ist kein Thema. Das ursprüngliche Poster sucht nach einer PHP-Lösung. Und meine Antwort ist eine Möglichkeit, dieses Problem anzugehen.Und auf Stack Overflow ist es gut für mehrere Antworten, denn wenn jemand in der Zukunft darüber stolpert, ist es gut für sie, alle gültigen Optionen zu überprüfen. Meins ist eine gültige Option sowie die 'zx81'-Lösung. – JakeGould

+0

Es sollte nicht gültig sein, wenn ich etwas wie "! Jóhn" eingib. Die ganze Zeichenfolge soll nur Alphabuchstaben und/oder akzentuierte Varianten sein. –

3

Ich würde diesen kompakten regex vorschlagen:

(?i)(?:(?![×Þß÷þø])[a-zÀ-ÿ])+ 

demo See.

  1. Diese Regex sich die Tatsache zunutze nimmt, dass die Umlaute Sie alle wollen scheinen À-ÿ im Unicode-Zeichenbereich zu leben (siehe diese table), so dass wir sie einfach in die Zeichenklasse hinzuzufügen.
  2. Die À-ÿ hat ein paar unerwünschte Zeichen. Im Gegensatz zu einigen Motoren ist PCRE (PHP Regex-Engine) nicht Zeichenklasse Subtraktion unterstützen, aber wir nachahmen es mit der negativen Look-Ahead-(?![×Þß÷þø])
  3. Beachten Sie, dass einige Zeichen wie à können durch mehr Unicode-Codepunkte (die à grapheme, oder ein a mit einem schweren Akzent). Dies passt nur zu den nicht kombinierten Graphemen. Alle Variationen zu fangen ist sehr schwer.

In Ihrem Code:

$regex = "~(?i)(?:(?![×Þß÷þø])[a-zÀ-ÿ])+~u"; 
$hit = preg_match($regex,$subject,$match); 
+0

Das ist großartig! Es funktionierte nicht in JavaScript, diese Modifikation funktioniert in PCRE, JavaScript und Python: (?: (?! [× ÞÞ ÷ þø]) [a-zA-ZÀ-ÿ]) + –

+0

@JuanGarcia Ja, das ist ein schöne Art, es zu tun. Ich verwende diese Methode häufig für benutzerdefinierte Bereiche. Danke für die Upvote BTW (ich nehme an, du warst es. :)) – zx81

+0

Bitte, aktualisieren Sie die Antwort, um alle zu unterstützen. Das kann für jemand anderen nützlich sein. –

1

kam ich mit der folgenden Lösung auf eine Kombination aus preg_match und iconv verwenden. Getestet mit PHP 5.5 unter Windows und Linux:

$testWords = array(
    // pass 
    'Çákë', 
    'JohnDoe', 
    'Fübar', 
    'Lòrem', 
    'FírstNäme', 
    // fail 
    'Ç@kë', 
    'J0hnDoe', 
    'F行bar', 
    'L高rem', 
    'F前rstNäme', 
    'Ç学kë', 
    '0' 
); 

$matchedWords = array_filter($testWords, function ($word) { 
    // these characters should not be in the search string but may appear after iconv conversion 
    $regexCharsNot = '\^~"`\''; 

    $valid = false; 

    if (!preg_match("/[$regexCharsNot]/u", $word)) { 
     if ($word = @iconv('UTF-8', 'ASCII//TRANSLIT', $word)) { 
      $valid = preg_match("/^[A-Za-z$regexCharsNot]+$/u", $word); 
     } 
    } 

    return $valid; 
}); 

echo print_r($matchedWords, true); 

/* 
Array 
(
    [0] => Çákë 
    [1] => JohnDoe 
    [2] => Fübar 
    [3] => Lòrem 
    [4] => FírstNäme 
) 
*/ 

iconv und ASCII//TRANSLIT führt irrelevante Zeichen, weshalb die $regexCharsNot Doppel Validierung erforderlich ist. Ich kam mit dieser Liste mit den folgenden:

// mb_str_split regex   http://www.php.net/manual/en/function.mb-split.php#99851 
// list of accented characters http://fasforward.com/list-of-european-special-characters/ 

$accentedCharacters = preg_split(
    '/(?<!^)(?!$)/u', 
    'ÄäÀàÁáÂâÃãÅåĄąĂăÆæÇçĆćĈĉČčĎđĐďðÈèÉéÊêËëĚěĘęĜĝĢģĤĥÌìÍíÎîÏïĴĵĶķĹĺĻļŁłĽľÑñŃńŇňÖöÒòÓóÔôÕõŐőØøŒœŔŕŘřߌśŜŝŞşŠšŤťŢţÞþÜüÙùÚúÛûŰűŨũŲųŮůŴŵÝýŸÿŶŷŹźŽžŻż'); 

/* 
$unsupported = ''; // 'Ǎǎẞ'; 

foreach ($accentedCharacters as $c) { 
    if ([email protected]('UTF-8', 'ASCII//TRANSLIT', $c)) { 
     $unsupported .= $c; 
    } 
} 
*/ 
+0

+1 für eine interessante Idee, aber meintest du für '^ ~' '' ''' (typo)? – zx81

Verwandte Themen