Заданные имена в верхнем регистре преобразуются в Собственный регистр, обрабатывая "О'Хара", "Макдональд", "Ван дер Слот" и т. Д.
Мне предоставлен список имен в верхнем регистре. С целью приветствия в электронном письме я хотел бы, чтобы они были надлежащим образом.
Достаточно легко сделать это с помощью PHP Ucwords. Но я чувствую, что мне нужна некоторая функция регулярного выражения для обработки распространенных исключений, таких как:
"О'Хара", "Макдональд", "ван дер Слот" и т. Д.
Это не так сильно, что мне нужна помощь в создании оператора регулярных выражений для обработки трех приведенных выше примеров (хотя это было бы неплохо), поскольку я не знаю, какими могут быть все распространенные исключения.
Конечно, кто-то сталкивался с этой проблемой раньше, какие-либо ссылки на опубликованные решения или что-то, что вы могли бы поделиться?
3 ответа
Использование регулярных выражений в коротком предоставленном списке может быть простым, но если вам нужно обрабатывать сотни или тысячи записей, очень трудно быть пуленепробиваемым.
Я бы предпочел использовать то, что не может повлиять на кого-то другого. Как узнать, предпочитает ли мистер "Макдональд" "Макдональд"?
Вы исправляете чужую ошибку. Если источник не может быть исправлен, вы можете использовать что-то вроде этого:
<?php
$provided_names = array(
"SMITH",
"O'HARA",
"MCDONALD",
"JONES",
"VAN DER SLOOT",
"MACDONALD"
);
$corrected_names = array(
"O'HARA" => "O'Hara",
"MCDONALD" => "McDonald",
"VAN DER SLOOT" => "van der Sloot"
);
$email_text = array();
foreach ($provided_names as $provided_name)
{
$provided_name = !array_key_exists($provided_name, $corrected_names)
? ucwords(strtolower($provided_name))
: $corrected_names[$provided_name];
$email_text[] = "{$provided_name}, your message text.";
}
print_r($email_text);
/* output:
Array
(
[0] => Smith, your message text.
[1] => O'Hara, your message text.
[2] => McDonald, your message text.
[3] => Jones, your message text.
[4] => van der Sloot, your message text.
[5] => Macdonald, your message text.
)
*/
?>
Я надеюсь, что это будет полезно.
Я написал небольшую библиотеку для этого: https://github.com/tamtamchik/namecase Вы можете установить его с помощью Composer.
Для ваших входов он производит именно то, что вам нужно, используя следующий код:
<?php
require_once 'vendor/autoload.php'; // Composer autoload
$arr = ["O'HARA", "MCDONALD", "VAN DER SLOOT"];
foreach ($arr as $name) {
echo $name . ' => ' . str_name_case($name) . PHP_EOL;
}
Функция вызова str_name_case
он поставляется с библиотекой lib для любой строки имени и будет преобразован в соответствующий регистр. Для ваших примеров выводом станет:
О'ХАРА => О'Хара
Макдональд => Макдональд
VAN DER SLOOT => ван дер Слот
Я написал это сегодня, чтобы реализовать в приложении, над которым я работаю. Я думаю, что этот код довольно понятен с комментариями. Он не на 100% точен во всех случаях, но легко справится с большинством ваших западных имен.
Примеры:
mary-jane => Mary-Jane
o'brien => O'Brien
Joël VON WINTEREGG => Joël von Winteregg
jose de la acosta => Jose de la Acosta
Код является расширяемым в том смысле, что вы можете добавить любое строковое значение в массив в верхней части, чтобы удовлетворить ваши потребности. Пожалуйста, изучите его и добавьте любые специальные функции, которые могут потребоваться.
function name_title_case($str)
{
// name parts that should be lowercase in most cases
$ok_to_be_lower = array('av','af','da','dal','de','del','der','di','la','le','van','der','den','vel','von');
// name parts that should be lower even if at the beginning of a name
$always_lower = array('van', 'der');
// Create an array from the parts of the string passed in
$parts = explode(" ", mb_strtolower($str));
foreach ($parts as $part)
{
(in_array($part, $ok_to_be_lower)) ? $rules[$part] = 'nocaps' : $rules[$part] = 'caps';
}
// Determine the first part in the string
reset($rules);
$first_part = key($rules);
// Loop through and cap-or-dont-cap
foreach ($rules as $part => $rule)
{
if ($rule == 'caps')
{
// ucfirst() words and also takes into account apostrophes and hyphens like this:
// O'brien -> O'Brien || mary-kaye -> Mary-Kaye
$part = str_replace('- ','-',ucwords(str_replace('-','- ', $part)));
$c13n[] = str_replace('\' ', '\'', ucwords(str_replace('\'', '\' ', $part)));
}
else if ($part == $first_part && !in_array($part, $always_lower))
{
// If the first part of the string is ok_to_be_lower, cap it anyway
$c13n[] = ucfirst($part);
}
else
{
$c13n[] = $part;
}
}
$titleized = implode(' ', $c13n);
return trim($titleized);
}