El algoritmo de Ollie fue un buen comienzo, pero no aplicó las marcas correctamente. Por ejemplo, qiao1 se convirtió en qīāō. Este es correcto y completo. Puede ver fácilmente cómo se definen las reglas de reemplazo.
Hace todo para el tono 5 también, aunque no afecta la salida, excepto para eliminar el número. Lo dejé en, en caso de que quiera hacer algo con tono 5.
El algoritmo funciona de la siguiente manera:
- La palabra y el tono están dentro de $ partido [1] y [2]
- Se agrega una estrella detrás de la letra que debe obtener la marca de acento
- Una letra con una estrella se reemplaza por esa letra con la marca de tono correcta.
Ejemplo:
qiao => (iao becomes ia*o) => qia*o => qiǎo
Esta estrategia, y el uso de strtr
(que da prioridad a los reemplazos más largos), se asegura de que esto no sucederá:
qiao1 => Qiao
function pinyin_addaccents($string) {
# Find words with a number behind them, and replace with callback fn.
return preg_replace_callback(
'~([a-zA-ZüÜ]+)(\d)~',
'pinyin_addaccents_cb',
$string);
}
# Helper callback
function pinyin_addaccents_cb($match) {
static $accentmap = null;
if($accentmap === null) {
# Where to place the accent marks
$stars =
'a* e* i* o* u* ü* '.
'A* E* I* O* U* Ü* '.
'a*i a*o e*i ia* ia*o ie* io* iu* '.
'A*I A*O E*I IA* IA*O IE* IO* IU* '.
'o*u ua* ua*i ue* ui* uo* üe* '.
'O*U UA* UA*I UE* UI* UO* ÜE*';
$nostars = str_replace('*', '', $stars);
# Build an array like Array('a' => 'a*') and store statically
$accentmap = array_combine(explode(' ',$nostars), explode(' ', $stars));
unset($stars, $nostars);
}
static $vowels =
Array('a*','e*','i*','o*','u*','ü*','A*','E*','I*','O*','U*','Ü*');
static $pinyin = Array(
1 => Array('ā','ē','ī','ō','ū','ǖ','Ā','Ē','Ī','Ō','Ū','Ǖ'),
2 => Array('á','é','í','ó','ú','ǘ','Á','É','Í','Ó','Ú','Ǘ'),
3 => Array('ǎ','ě','ǐ','ǒ','ǔ','ǚ','Ǎ','Ě','Ǐ','Ǒ','Ǔ','Ǚ'),
4 => Array('à','è','ì','ò','ù','ǜ','À','È','Ì','Ò','Ù','Ǜ'),
5 => Array('a','e','i','o','u','ü','A','E','I','O','U','Ü')
);
list(,$word,$tone) = $match;
# Add star to vowelcluster
$word = strtr($word, $accentmap);
# Replace starred letter with accented
$word = str_replace($vowels, $pinyin[$tone], $word);
return $word;
}
información adicional para aquellos que buscan en este :! (del artículo de Wikipedia http://en.wikipedia.org/wiki/Pinyin) un algoritmo para encontrar la letra vocal correcta (cuando hay más de uno) es la siguiente: 1. Si hay una "a" o un " e "que se llevará a la marca del tono. 2. Si hay un" ou "entonces el" o "la toma tono de marca. 3. De lo contrario, la segunda vocal lleva la marca del tono. –