如何从PHP字符串中的字符中删除重音?

geo*_*ock 81 php iconv

我试图从PHP字符串中的字符中删除重音符号作为使字符串在URL中可用的第一步.

我正在使用以下代码:

$input = "Fóø Bår";

setlocale(LC_ALL, "en_US.utf8");
$output = iconv("utf-8", "ascii//TRANSLIT", $input);

print($output);
Run Code Online (Sandbox Code Playgroud)

我期望的输出将是这样的:

F'oo Bar
Run Code Online (Sandbox Code Playgroud)

但是,不是重音字符被音译,而是用问号代替:

F?? B?r
Run Code Online (Sandbox Code Playgroud)

我在网上找到的所有内容都表明设置语言环境将解决这个问题,但我已经这样做了.我已经检查了以下细节:

  1. 我正在设置的语言环境由服务器支持(包含在生成的列表中locale -a)
  2. 服务器的iconv版本(包括在生成的列表中)支持源和目标编码(UTF-8和ASCII iconv -l)
  3. 输入字符串是UTF-8编码的(使用PHP mb_check_encoding函数验证,如mercator答案中所建议的那样)
  4. 呼叫setlocale成功(返回'en_US.utf8'而不是FALSE)

问题的原因:

服务器正在使用iconv的错误实现.它有glibc版本而不是所需的libiconv版本.

请注意,某些系统上的iconv功能可能无法正常工作.在这种情况下,安装GNU libiconv库是个好主意.它最有可能最终得到更一致的结果.
- PHP手册对iconv的介绍

有关PHP使用的iconv实现的详细信息包含在phpinfo函数的输出中.

(我无法使用正在为此项目工作的服务器上的正确iconv库重新编译PHP,因此下面我接受的答案是在没有iconv支持的情况下删除重音的最有用的答案.)

dyn*_*mic 80

WordPress实现怎么样?

function remove_accents($string) {
    if ( !preg_match('/[\x80-\xff]/', $string) )
        return $string;

    $chars = array(
    // Decompositions for Latin-1 Supplement
    chr(195).chr(128) => 'A', chr(195).chr(129) => 'A',
    chr(195).chr(130) => 'A', chr(195).chr(131) => 'A',
    chr(195).chr(132) => 'A', chr(195).chr(133) => 'A',
    chr(195).chr(135) => 'C', chr(195).chr(136) => 'E',
    chr(195).chr(137) => 'E', chr(195).chr(138) => 'E',
    chr(195).chr(139) => 'E', chr(195).chr(140) => 'I',
    chr(195).chr(141) => 'I', chr(195).chr(142) => 'I',
    chr(195).chr(143) => 'I', chr(195).chr(145) => 'N',
    chr(195).chr(146) => 'O', chr(195).chr(147) => 'O',
    chr(195).chr(148) => 'O', chr(195).chr(149) => 'O',
    chr(195).chr(150) => 'O', chr(195).chr(153) => 'U',
    chr(195).chr(154) => 'U', chr(195).chr(155) => 'U',
    chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y',
    chr(195).chr(159) => 's', chr(195).chr(160) => 'a',
    chr(195).chr(161) => 'a', chr(195).chr(162) => 'a',
    chr(195).chr(163) => 'a', chr(195).chr(164) => 'a',
    chr(195).chr(165) => 'a', chr(195).chr(167) => 'c',
    chr(195).chr(168) => 'e', chr(195).chr(169) => 'e',
    chr(195).chr(170) => 'e', chr(195).chr(171) => 'e',
    chr(195).chr(172) => 'i', chr(195).chr(173) => 'i',
    chr(195).chr(174) => 'i', chr(195).chr(175) => 'i',
    chr(195).chr(177) => 'n', chr(195).chr(178) => 'o',
    chr(195).chr(179) => 'o', chr(195).chr(180) => 'o',
    chr(195).chr(181) => 'o', chr(195).chr(182) => 'o',
    chr(195).chr(182) => 'o', chr(195).chr(185) => 'u',
    chr(195).chr(186) => 'u', chr(195).chr(187) => 'u',
    chr(195).chr(188) => 'u', chr(195).chr(189) => 'y',
    chr(195).chr(191) => 'y',
    // Decompositions for Latin Extended-A
    chr(196).chr(128) => 'A', chr(196).chr(129) => 'a',
    chr(196).chr(130) => 'A', chr(196).chr(131) => 'a',
    chr(196).chr(132) => 'A', chr(196).chr(133) => 'a',
    chr(196).chr(134) => 'C', chr(196).chr(135) => 'c',
    chr(196).chr(136) => 'C', chr(196).chr(137) => 'c',
    chr(196).chr(138) => 'C', chr(196).chr(139) => 'c',
    chr(196).chr(140) => 'C', chr(196).chr(141) => 'c',
    chr(196).chr(142) => 'D', chr(196).chr(143) => 'd',
    chr(196).chr(144) => 'D', chr(196).chr(145) => 'd',
    chr(196).chr(146) => 'E', chr(196).chr(147) => 'e',
    chr(196).chr(148) => 'E', chr(196).chr(149) => 'e',
    chr(196).chr(150) => 'E', chr(196).chr(151) => 'e',
    chr(196).chr(152) => 'E', chr(196).chr(153) => 'e',
    chr(196).chr(154) => 'E', chr(196).chr(155) => 'e',
    chr(196).chr(156) => 'G', chr(196).chr(157) => 'g',
    chr(196).chr(158) => 'G', chr(196).chr(159) => 'g',
    chr(196).chr(160) => 'G', chr(196).chr(161) => 'g',
    chr(196).chr(162) => 'G', chr(196).chr(163) => 'g',
    chr(196).chr(164) => 'H', chr(196).chr(165) => 'h',
    chr(196).chr(166) => 'H', chr(196).chr(167) => 'h',
    chr(196).chr(168) => 'I', chr(196).chr(169) => 'i',
    chr(196).chr(170) => 'I', chr(196).chr(171) => 'i',
    chr(196).chr(172) => 'I', chr(196).chr(173) => 'i',
    chr(196).chr(174) => 'I', chr(196).chr(175) => 'i',
    chr(196).chr(176) => 'I', chr(196).chr(177) => 'i',
    chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij',
    chr(196).chr(180) => 'J', chr(196).chr(181) => 'j',
    chr(196).chr(182) => 'K', chr(196).chr(183) => 'k',
    chr(196).chr(184) => 'k', chr(196).chr(185) => 'L',
    chr(196).chr(186) => 'l', chr(196).chr(187) => 'L',
    chr(196).chr(188) => 'l', chr(196).chr(189) => 'L',
    chr(196).chr(190) => 'l', chr(196).chr(191) => 'L',
    chr(197).chr(128) => 'l', chr(197).chr(129) => 'L',
    chr(197).chr(130) => 'l', chr(197).chr(131) => 'N',
    chr(197).chr(132) => 'n', chr(197).chr(133) => 'N',
    chr(197).chr(134) => 'n', chr(197).chr(135) => 'N',
    chr(197).chr(136) => 'n', chr(197).chr(137) => 'N',
    chr(197).chr(138) => 'n', chr(197).chr(139) => 'N',
    chr(197).chr(140) => 'O', chr(197).chr(141) => 'o',
    chr(197).chr(142) => 'O', chr(197).chr(143) => 'o',
    chr(197).chr(144) => 'O', chr(197).chr(145) => 'o',
    chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe',
    chr(197).chr(148) => 'R',chr(197).chr(149) => 'r',
    chr(197).chr(150) => 'R',chr(197).chr(151) => 'r',
    chr(197).chr(152) => 'R',chr(197).chr(153) => 'r',
    chr(197).chr(154) => 'S',chr(197).chr(155) => 's',
    chr(197).chr(156) => 'S',chr(197).chr(157) => 's',
    chr(197).chr(158) => 'S',chr(197).chr(159) => 's',
    chr(197).chr(160) => 'S', chr(197).chr(161) => 's',
    chr(197).chr(162) => 'T', chr(197).chr(163) => 't',
    chr(197).chr(164) => 'T', chr(197).chr(165) => 't',
    chr(197).chr(166) => 'T', chr(197).chr(167) => 't',
    chr(197).chr(168) => 'U', chr(197).chr(169) => 'u',
    chr(197).chr(170) => 'U', chr(197).chr(171) => 'u',
    chr(197).chr(172) => 'U', chr(197).chr(173) => 'u',
    chr(197).chr(174) => 'U', chr(197).chr(175) => 'u',
    chr(197).chr(176) => 'U', chr(197).chr(177) => 'u',
    chr(197).chr(178) => 'U', chr(197).chr(179) => 'u',
    chr(197).chr(180) => 'W', chr(197).chr(181) => 'w',
    chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y',
    chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z',
    chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z',
    chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z',
    chr(197).chr(190) => 'z', chr(197).chr(191) => 's'
    );

    $string = strtr($string, $chars);

    return $string;
}
Run Code Online (Sandbox Code Playgroud)

要更好地理解此函数的作用,请在此处检查相应的转换表:

À => A
Á => A
 => A
à => A
Ä => A
Å => A
Ç => C
È => E
É => E
Ê => E
Ë => E
Ì => I
Í => I
Î => I
Ï => I
Ñ => N
Ò => O
Ó => O
Ô => O
Õ => O
Ö => O
Ù => U
Ú => U
Û => U
Ü => U
Ý => Y
ß => s
à => a
á => a
â => a
ã => a
ä => a
å => a
ç => c
è => e
é => e
ê => e
ë => e
ì => i
í => i
î => i
ï => i
ñ => n
ò => o
ó => o
ô => o
õ => o
ö => o
ù => u
ú => u
û => u
ü => u
ý => y
ÿ => y
? => A
? => a
? => A
? => a
? => A
? => a
? => C
? => c
? => C
? => c
? => C
? => c
? => C
? => c
? => D
? => d
? => D
? => d
? => E
? => e
? => E
? => e
? => E
? => e
? => E
? => e
? => E
? => e
? => G
? => g
? => G
? => g
? => G
? => g
? => G
? => g
? => H
? => h
? => H
? => h
? => I
? => i
? => I
? => i
? => I
? => i
? => I
? => i
? => I
? => i
? => IJ
? => ij
? => J
? => j
? => K
? => k
? => k
? => L
? => l
? => L
? => l
? => L
? => l
? => L
? => l
? => L
? => l
? => N
? => n
? => N
? => n
? => N
? => n
? => N
? => n
? => N
? => O
? => o
? => O
? => o
? => O
? => o
Œ => OE
œ => oe
? => R
? => r
? => R
? => r
? => R
? => r
? => S
? => s
? => S
? => s
? => S
? => s
Š => S
š => s
? => T
? => t
? => T
? => t
? => T
? => t
? => U
? => u
? => U
? => u
? => U
? => u
? => U
? => u
? => U
? => u
? => U
? => u
? => W
? => w
? => Y
? => y
Ÿ => Y
? => Z
? => z
? => Z
? => z
Ž => Z
ž => z
? => s
Run Code Online (Sandbox Code Playgroud)

您可以通过简单地迭代$chars函数数组来自己生成此转换表:

foreach($chars as $k=>$v) {
   printf("%s -> %s", $k, $v);
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案,因为它是以更安全的方式实现的(使用chr()函数)而不是硬编码重音字符,这可能会在某些文本编辑器中被覆盖. (3认同)
  • 应该注意的是,WordPress是GPLv2许可的。 (3认同)
  • 请注意,新实现现在位于:https://core.trac.wordpress.org/browser/tags/4.1/src/wp-includes/formatting.php#L822.该代码需要提供par wordpress核心的其他功能,并且不能在没有(轻)工作的情况下进行复制/粘贴. (2认同)

Gin*_*ino 42

这是我经常发现和使用的一段代码:

function stripAccents($stripAccents){
  return strtr($stripAccents,'àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ','aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY');
}
Run Code Online (Sandbox Code Playgroud)

  • 由于`strtr()`不是多字节识别的,如果您的脚本文件以多字节格式(例如UTF-8)编码,则此函数会产生错误的结果. (13认同)
  • ...此外-此列表不包含**许多带重音符号的字符,例如`ů,ž,ř,č,...` (2认同)

Caz*_*nti 32

Gino上面发布的UTF-8友好版简单功能:

function stripAccents($str) {
    return strtr(utf8_decode($str), utf8_decode('àáâãäçèéêëìíîïñòóôõöùúûüýÿÀÁÂÃÄÇÈÉÊËÌÍÎÏÑÒÓÔÕÖÙÚÛÜÝ'), 'aaaaaceeeeiiiinooooouuuuyyAAAAACEEEEIIIINOOOOOUUUUY');
}
Run Code Online (Sandbox Code Playgroud)

不得不来这个因为我的php文件是UTF-8编码的.

希望能帮助到你.

  • 请注意,自 PHP 8.2.0 起,`utf8_decode` 已被弃用,不应再使用。 (3认同)

lan*_*vel 14

使用时iconv,必须设置参数区域设置:

function test_enc($text = '?š??žýáíé ?Š??ŽÝÁÍÉ fóø bår FÓØ BÅR æ')
{
    echo '<tt>';
    echo iconv('utf8', 'ascii//TRANSLIT', $text);
    echo '</tt><br/>';
} 

test_enc();
setlocale(LC_ALL, 'cs_CZ.utf8');
test_enc();
setlocale(LC_ALL, 'en_US.utf8');
test_enc();
Run Code Online (Sandbox Code Playgroud)

产量为:

????????? ????????? f?? b?r F?? B?R ae
escrzyaie ESCRZYAIE fo? bar FO? BAR ae
escrzyaie ESCRZYAIE fo? bar FO? BAR ae
Run Code Online (Sandbox Code Playgroud)

另一个语言环境,然后cs_CZ和en_US我还没有安装,我无法测试它.

在C#中,我看到使用转换为unicode规范化形式的解决方案 - 重音被拆分,然后通过非间隔unicode类别进行过滤.


gab*_*abo 13

如果你有http://php.net/manual/en/book.intl.php可用,这解决了你的问题

$string = "Fóø Bår";
$transliterator = Transliterator::createFromRules(':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: Lower(); :: NFC;', Transliterator::FORWARD);
echo $normalized = $transliterator->transliterate($string);
Run Code Online (Sandbox Code Playgroud)

  • 在这种情况下不需要 `Lower()` (3认同)
  • 我已经读了十几遍了,直到今天我还是错过了这个完美的答案! (2认同)
  • 不敢相信最受欢迎的答案是关于硬编码字符映射的。**这**应该是公认的答案。 (2认同)

Wai*_*rim 12

最简单的方法是使用iconv()PHP本机函数.

 echo iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', "Thîs îs à vêry wrong séntènce!");

 // output: This is a very wrong sentence!
Run Code Online (Sandbox Code Playgroud)

  • 这不是很可靠 `echo iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', 'usuario o contraseña dependentos');` 输出 `usuario o contrase?a unavailable` (4认同)
  • 对于您的示例,您可以使用: `setlocale(LC_CTYPE, 'cs_CZ'); echo iconv('UTF-8', 'ASCII//TRANSLIT', "usuario o contraseña invalidos"); // 输出:usuario o contrasena invalidos`。请参阅 PHP 文档以获取更多信息。一切都在那里!http://php.net/manual/en/function.iconv.php (3认同)
  • iconv UTF8 到 ASCII 的音译似乎很奇怪。我的语言环境得到“usuario o contrase~na unavailable”。它将 ñ 转换为 ~n 和 ö 转换为 :o 我发现音译为 latin1 然后手动转换扩展 ascii 效果最好。 (2认同)

Xet*_*ius 6

你可以使用urlencode.不完全做你想要的(删除重音),但会给你一个url可用的字符串

$output = urlencode ($input);
Run Code Online (Sandbox Code Playgroud)

在Perl中我可以使用翻译正则表达式,但我不能想到PHP的等价物

$input =~ tr/áâàå/aaaa/;
Run Code Online (Sandbox Code Playgroud)

等等...

你可以用preg_replace做到这一点

$patterns[0] = '/[á|â|à|å|ä]/';
$patterns[1] = '/[ð|é|ê|è|ë]/';
$patterns[2] = '/[í|î|ì|ï]/';
$patterns[3] = '/[ó|ô|ò|ø|õ|ö]/';
$patterns[4] = '/[ú|û|ù|ü]/';
$patterns[5] = '/æ/';
$patterns[6] = '/ç/';
$patterns[7] = '/ß/';
$replacements[0] = 'a';
$replacements[1] = 'e';
$replacements[2] = 'i';
$replacements[3] = 'o';
$replacements[4] = 'u';
$replacements[5] = 'ae';
$replacements[6] = 'c';
$replacements[7] = 'ss';

$output = preg_replace($patterns, $replacements, $input);
Run Code Online (Sandbox Code Playgroud)

(请注意,这是从周五中午记忆后的迷雾啤酒中输入的,所以可能不是100%正确)

或者你可以制作一个哈希表并根据它进行替换.

  • php相当于tr/.../...是strtr (3认同)

Jun*_*r M 6

确实是一个品味问题.转换这些字母有很多种口味.

function replaceAccents($str)
{
  $a = array('À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ð', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'Ý', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ý', 'ÿ', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 'Œ', 'œ', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 'Š', 'š', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 'Ÿ', '?', '?', '?', '?', 'Ž', 'ž', '?', 'ƒ', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?');
  $b = array('A', 'A', 'A', 'A', 'A', 'A', 'AE', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'D', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 's', 'a', 'a', 'a', 'a', 'a', 'a', 'ae', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'u', 'y', 'y', 'A', 'a', 'A', 'a', 'A', 'a', 'C', 'c', 'C', 'c', 'C', 'c', 'C', 'c', 'D', 'd', 'D', 'd', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'E', 'e', 'G', 'g', 'G', 'g', 'G', 'g', 'G', 'g', 'H', 'h', 'H', 'h', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'I', 'i', 'IJ', 'ij', 'J', 'j', 'K', 'k', 'L', 'l', 'L', 'l', 'L', 'l', 'L', 'l', 'l', 'l', 'N', 'n', 'N', 'n', 'N', 'n', 'n', 'O', 'o', 'O', 'o', 'O', 'o', 'OE', 'oe', 'R', 'r', 'R', 'r', 'R', 'r', 'S', 's', 'S', 's', 'S', 's', 'S', 's', 'T', 't', 'T', 't', 'T', 't', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'W', 'w', 'Y', 'y', 'Y', 'Z', 'z', 'Z', 'z', 'Z', 'z', 's', 'f', 'O', 'o', 'U', 'u', 'A', 'a', 'I', 'i', 'O', 'o', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'U', 'u', 'A', 'a', 'AE', 'ae', 'O', 'o');
  return str_replace($a, $b, $str);
}
Run Code Online (Sandbox Code Playgroud)


Mim*_*uni 6

这是一个简单的函数,我通常用来删除重音:

function str_without_accents($str, $charset='utf-8')
{
    $str = htmlentities($str, ENT_NOQUOTES, $charset);

    $str = preg_replace('#&([A-za-z])(?:acute|cedil|caron|circ|grave|orn|ring|slash|th|tilde|uml);#', '\1', $str);
    $str = preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $str); // pour les ligatures e.g. '&oelig;'
    $str = preg_replace('#&[^;]+;#', '', $str); // supprime les autres caractères

    return $str;   // or add this : mb_strtoupper($str); for uppercase :)
}
Run Code Online (Sandbox Code Playgroud)


Jer*_*yth 5

我认为这里的问题是你的编码将ä和å不同的符号视为'a'.事实上,strtr的PHP文档提供了一个用于删除重音符号的示例:(

http://ie2.php.net/strtr

  • iconv调用中的// TRANSLIT旨在转换为目标编码中最近的可用替代方案.这应该包括删除重音,或将单个字符转换为两个,例如ñ可能会变成n~ (3认同)
  • @karim79 `mb_strstr` 是错误的函数,并且没有 `mb_strtr` (3认同)
  • 我认为您应该建议使用mb_strstr(),因为他的输入是UTF8 (2认同)