微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从音译转换中排除特定字符

如何解决从音译转换中排除特定字符

我正在尝试使用 PHP 进行音译,但我需要的是转换所有非拉丁字符,但保留意大利重音字符 (àèìòù)。

PHP Transliterator 缺少文档和在线示例。 我已经阅读了 ICU docs 并且我知道有一条规则会强制 Transliterator 将一个字符转换为我们指定的另一个字符 (à > b)。

代码(使用 create 函数

$str = "AŠAàèìòù Chén Hǎi yáo München Faißt Финиш 国内 - 镜像";
$transliterator = Transliterator::create("Any-Latin; Latin-ASCII");
echo $transliterator->transliterate($str);

将所有非拉丁字符转换为拉丁字符(带有所有重音字符)并给出结果

ASAaeIoU Chen Hai yao Munchen Faisst Finis guo nei - jing xiang

代码(使用 createFromrules 函数

$str = "AŠAàèìòù Chén Hǎi yáo München Faißt Финиш 国内 - 镜像";
$transliterator = Transliterator::createFromrules("á>b");
echo $transliterator->transliterate($str);

强制正确地将 à 转换为 b,但是,显然,没有由前面的代码进行的转换 Any-Latin; Latin-ASCII,给出结果

AŠAbèìòù Chén Hǎi ybo München Faißt Финиш 国内 - 镜像

所以我的目标是合并 Any-Latin; Latin-ASCII 转换和 à > à 规则(以及其他意大利语重音元音),以便告诉 Transliterator 将所有非拉丁字符转换为拉丁字符,但将意大利语转换为重读元音,结果如下:

ASAàèìòù Chen Hai yao Munchen Faisst Finis guo nei - jing xiang

有没有办法将 à>à 规则放在 create 函数的参数中或在 Any-Latin; Latin-ASCII 函数的参数中添加 createFromrules 指令?

解决方法

您可以使用 preg_replace_callback 过滤除意大利语重音字符之外的所有字符并对其应用音译。

,

以输入和输出为例:

$transliterator = Transliterator::create("Any-Latin; Latin-ASCII");
$str = "AŠAàèìòù Chén Hǎi yáo München Faißt Финиш 国内 - 镜像";
echo $transliterator->transliterate($str),"\n";
ASAaeiou Chen Hai yao Munchen Faisst Finis guo nei - jing xiang

当仅对与您指定保留的字符范围(意大利重音字符 [àèìòù])不匹配的段应用音译时,它应该提供结果。

一种选择是使用 preg_replace_callback

应用音译需要回调:

$transliterate = static function (array $match) use ($transliterator) {
    return $transliterator->transliterate($match[0]);
};

而且它需要有一个模式来匹配除要保留的字符之外的所有内容。它需要正确定义并与 Unicode 兼容:

([^\xE0\xE8\xEC\xF2\xF9]+)ui


(...)                : delimiters: the regular expression is inside
u                    : modifier: u - Unicode mode (UTF-8 encoding in
                       PHP,PCRE_UTF8)
i                    : modifier: i - letters in the pattern match
                       both upper and lower case letters
                       (PCRE_CASELESS)

[^...]               : character class: not matching any of the
                       characters (`^`); negated character class
\xE0\xE8\xEC\xF2\xF9 : the italian accented characters àèìòù written
                       in a stable notation (you can easily copy and
                       paste it for example)

最后但并非最不重要的一点是,要操作的对象必须与要保留的字符兼容。由于在 Unicode 中可以有多种方法来编写相同的字符,因此输入被规范化以与 PCRE 模式兼容

echo preg_replace_callback(
    '([^\xE0\xE8\xEC\xF2\xF9]+)ui',$transliterate,Normalizer::normalize($str,Normalizer::NFC)
),"\n";

输出:

ASAàèìòù Chen Hai yao Munchen Faisst Finis guo nei - jing xiang

Example across PHP versions


附录:

  • \xE0\xE1\xE8\xE9\xEC\xED\xF2\xF3\xF9\xFA 意大利语重音字符的小写列表(可与 i 修饰符一起使用)
  • \xC0\xC1\xC8\xC9\xCC\xCD\xD2\xD3\xD9\xDA\xE0\xE1\xE8\xE9\xEC\xED\xF2\xF3\xF9\xFA 意大利语重音字符的小写和大写列表(可以在没有 i 修饰符的情况下使用)
  • PCRE 语法字符(摘录):
       \xhh       character with hex code hh
       \x{hhh..}  character with hex code hhh..
    
  • 链接到完整的 PCRE 语法:https://www.pcre.org/original/doc/html/pcresyntax.html
,

您所要做的就是删除 Latin-ASCII 规则。

$str = "AŠAàèìòù Chén Hǎi yáo München Faißt Финиш 国内 - 镜像";
$transliterator = Transliterator::create("Any-Latin; Any-NFC");
echo $transliterator->transliterate($str);

输出:

AŠAàèìòù Chén Hǎi yáo München Faißt Finiš guó nèi - jìng xiàng

您可能还想借此机会对字符串应用规范化规则,以将重音字符组合或分解为一致的形式,具体取决于您打算对它们做什么。

$str = "AŠAàèìòù Chén Hǎi yáo München Faißt Финиш 国内 - 镜像";
$none = Transliterator::create("Any-Latin");
$nfc = Transliterator::create("Any-Latin; Any-NFC");
$nfd = Transliterator::create("Any-Latin; Any-NFD");
var_dump(
    $none->transliterate($str),$nfc->transliterate($str),$nfd->transliterate($str)
);

输出:

string(78) "AŠAàèìòù Chén Hǎi yáo München Faißt Finiš guó nèi - jìng xiàng"
string(78) "AŠAàèìòù Chén Hǎi yáo München Faißt Finiš guó nèi - jìng xiàng"
string(93) "AŠAàèìòù Chén Hǎi yáo München Faißt Finiš guó nèi - jìng xiàng"

NFC 是“组合式”的,因为在所有具有单码点表示的重音字符中都是这样表示的。 NFD 被“分解”,所有重音字符都被拆分为它们的基本代码点和一个重音组合标记。在这两种情况下,单个基字符上的多个组合标记将以一致的方式排列。

有些文件系统需要某种形式,例如:Mac 需要 NFD,而有些文件系统会简单地接受任何东西,例如:ext,创建难以处理的混合组合的“重复”文件。

,

我在尝试避免不需要的音译时使用的一种方法 - 它有点丑陋,但工作量很小。用标签代替你不想音译的字符,然后在音译后替换它们:

<?php

$str = "AŠAàèìòù Chén Hǎi yáo München Faißt Финиш 国内 - 镜像";
$str = str_replace(['à','è','ì','ò','ù'],['@@a@@','@@e@@','@@i@@','@@o@@','@@u@@'],$str);
$transliterator = Transliterator::create("Any-Latin; Latin-ASCII");
$out = $transliterator->transliterate($str);
$out = str_replace(['@@a@@',['à',$out);
echo $out;

结果是:

ASAàèìòù Chen Hai yao Munchen Faisst Finis guo nei - jing xiang

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。