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



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

PHP 音译器缺乏文档和在线示例。 我读过 ICU 文档,我知道有一条规则强制音译器将一个字符转换为我们指定的另一个字符(à > 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转换和à > à规则(以及其他意大利语重音元音),以便告诉音译器将所有非拉丁字符转换为拉丁语,但将意大利语重音元音转换为自己,结果如下:

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

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

给定输入和输出的示例:

$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兼容:

([^xE0xE8xECxF2xF9]+)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
xE0xE8xECxF2xF9 : the italian accented characters àèìòù written
in a stable notation (you can easily copy and
paste it for example)

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

echo preg_replace_callback(
'([^xE0xE8xECxF2xF9]+)ui', 
$transliterate, 
Normalizer::normalize($str, Normalizer::NFC)
), "n";

输出:

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

跨 PHP 版本的示例。


附录:

  • xE0xE1xE8xE9xECxEDxF2xF3xF9xFA意大利语重音字符的小写列表(可与 i 修饰符一起使用)
  • xC0xC1xC8xC9xCCxCDxD2xD3xD9xDAxE0xE1xE8xE9xECxEDxF2xF3xF9xFA意大利语重音字符的小写和大写列表(可以在没有 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

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

您所要做的就是删除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@@', '@@e@@', '@@i@@', '@@o@@', '@@u@@'], ['à', 'è', 'ì', 'ò', 'ù'], $out);
echo $out;

结果是:

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

[编辑] 更简单:使用过滤器将更改仅应用于所选字符:

$str = 'AŠAàèìòù Chén Hǎi yáo München Faißt Финиш 国内 - 镜像';
$rules = <<<'RULES'
:: [^ÀàÈèÌìÒòÙù];
:: Any-Latin ;
:: Latin-ASCII ;
RULES;
$tls = Transliterator::createFromRules($rules);
echo $tls->transliterate($str), PHP_EOL;
// ASAàèìòù Chen Hai yao Munchen Faisst Finis guo nei - jing xiang

:: [^ÀàÈèÌìÒòÙù]是排除所选重音字母的筛选器。


[旧答案](这也有效)
您可以使用规范化来保护要在从Any音译为拉丁语之前保留的重音字符:

$str = 'AŠAàèìòù Chén Hǎi yáo München Faißt Финиш 国内 - 镜像';
$rules = <<<'RULES'
:: NFC ;
à > a ̀  ;
è > e ̀  ;
ì > i ̀  ;
ò > o ̀  ;
ù > u ̀  ;
:: Any-Latin   ;
:: [^ ̀ ]-ASCII ;
:: NFC ;
RULES;
$tls = Transliterator::createFromRules($rules);
echo $tls->transliterate($str), PHP_EOL;
// ASAàèìòù Chen Hai yao Munchen Faisst Finis guo nei - jing xiang

这样,要用重音字符保护的重音字符是唯一的分解形式(使用组合字符)。那些来自Any-Latin音译的都是组合形式(它们只使用一个码位)。 然后,您可以使用排除组合重音符的集合,而不是Latin-ASCII中的Latin

最新更新