匹配alpha字母和重音字母

时间:2014-06-22 22:56:33

标签: php regex unicode

我正在寻找这种模式的一些正则表达式代码:

  • 必须至少包含以下1项并匹配整个字符串。

  • 只能包含字母(a-z A-Z)......

  • 并带有重音的字母(áäàeta)。

我正在使用preg_match('/^([\p{L}]*)$/iu', $input),但\p{L}匹配所有unicode字母,包括中文。我只想允许英文字母以及它们的重音变体。

所以JohnDoeFübarLòremFírstNämeÇákë都是有效的输入,因为它们都包含至少1个字母和/或或带重音的字母,整个字符串匹配。

4 个答案:

答案 0 :(得分:3)

我会建议这个紧凑的正则表达式:

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

请参阅demo

  1. 这个正则表达式利用了这样一个事实:你想要的重音字母似乎都存在于从Àÿ的Unicode字符范围内(请参阅此table),所以我们只是将其添加到角色类。
  2. À-ÿ有一些不需要的字符。与某些引擎不同,PCRE(PHP的正则表达式引擎)不支持字符类减法,但我们使用负前瞻(?![×Þß÷þø])
  3. 来模仿它
  4. 请注意,某些字符(例如à)可以由多个Unicode代码点(à字形或带有重音符的a表示)。这只会匹配未合并的字素。抓住所有变化真的很难。
  5. 在您的代码中:

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

答案 1 :(得分:1)

使用您的样本数据以及一些中文&日语字符,正则表达式/[!\p{Common}\p{Latin}]*/iu似乎有效。有关详细信息,此网站在predefined Unicode categories上有一些不错的背景信息以及一个不错的simple explanation here。但它确实为此版本中的非拉丁字符返回空匹配。我在底部的 EDIT:中的那个最适合干净的布尔逻辑:

// 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);

}

输出如下:注意中文&日文字符返回空匹配。另请注意•••••••\p{Common}正则表达式匹配的结果。如果您不希望这样的常见字符出现,只需将正则表达式更改为/[!\p{Latin}]*/iu即可。我正在使用array_filter来清除那些空值,但它很笨拙。所以这不是完美的,但可以使用:

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

编辑:此测试代码使用上面发布的正则表达式的变体来消除上面的空不匹配问题; /(?:[\p{Latin}])+/iu。请注意,这仅适用于与\p{Latin}匹配,因此\p{Common}在这里效果不佳。但使用/(?:[\p{Latin}])+/iu的结果更清晰,并确保您可以使用preg_match的简单布尔检查来检查字符,而不必使用将$matches数组与{{1}混合的kludge }}:

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); } 在这些情况下将返回布尔值prey_match

false

答案 2 :(得分:1)

我使用preg_matchiconv的组合提出了以下解决方案。在Windows和Linux上使用php 5.5进行测试:

$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
)
 */

iconvASCII//TRANSLIT引入了无关的字符,这就是需要$regexCharsNot双重验证的原因。我使用以下内容提出了该列表:

// 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 (!@iconv('UTF-8', 'ASCII//TRANSLIT', $c)) {
        $unsupported .= $c;
    }
}
*/

答案 3 :(得分:0)

重音字母是由他们自己的unicode字符与他们的非重音变体完全无关。可能看到人类观察者彼此相关,但计算机无法通过将其与标准ascii集的字母字符进行比较来了解差异。 实现此目的的方法是通过白名单向您的正则表达式提供允许使用哪些字符。 如果你不需要带重音的字符,另一种方法是使用像Apache Lucene这样的库(这是一个Java库,但我认为我已经读过它可以在PHP中使用)将用它们的非重音变体取代重音字符合适的分析仪。