Доработать функцию PHP
мне нужно доработать функцию. Суть функции в том чтобы вначале каждого предложения первые буквы первых слов должны быть в верхнем регистре - функция есть, НО к примеру сокращенные слова например "т.д. т.п. др. г. чел." превращаются в "т.Д. т.П.". Я думаю можно сделать это через регулярные выражения, но я в них слаб, прошу помощи.
function upper_letter($text){
$exp = ['т.д.','т.п.','др.','г.','чел.','пр.'];
$str = $text;
$r = preg_replace_callback(
// добавляем модификатор u, чтобы регулярка работала с многобайтными кодировками (utf-8, utf-16)
"/\.\s*\w/u",
// на вход поступает каждое из найденных соответствий
function($m) {
// используем mb_ функцию, так как она работает с многобайтными кодировками
return mb_strtoupper($m[0]);
},
$str
);
echo $r;
}
upper_letter('Я охотник. Живу в лесу.И мне комфортно и т.п') //Я охотник. Живу в лесу.И мне комфортно и т.П
Ответы (2 шт):
Определитесь со списком исключений, и если он не слишком длинный, как указанный в функции массив $exp, можно доработать регулярное выражение следующим образом:
\b(?i:т\.д|т\.п|др|г|чел|пр|см)\b\.?(*SKIP)(*FAIL)|\.\s*\w
См. пример использования регулярного выражения
На самом деле, вам, скорее всего следует заменить \w (которое находит любые буквы, цифры и _) на \p{Ll}, которое находит только строчные буквы:
\b(?i:т\.д|т\.п|др|г|чел|пр|см)\b\.?(*SKIP)(*FAIL)|\.\s*\w
См. пример использования регулярного выражения.
Подробности
\b- граница слова(?i:т\.д|т\.п|др|г|чел|пр|см)- одна из строк,т.д,т.п,др,г,чел,прилисм\b- граница слова\.?- необязательный знак.(*SKIP)(*FAIL)- оператор, который очищает буфер текущего совпадения и запускает поиск нового совпадения с текущей позиции в строке|- или\.- точка\s*- 0 и более пробельных символов\p{Ll}- любая строчная буква
Обратите внимание на массив $exp = ['т.д','т.п','др','г','чел','пр', 'см'];, в котором конечные точки удалены (иначе регулярное выражение не сработает). implode("|", array_map(function($i) { return preg_quote(trim($i), "/"); }, $exp)) необходимо для экранирования точек.
Функция будет выглядеть следующим образом:
function upper_letter($text){
$exp = ['т.д','т.п','др','г','чел','пр', 'см'];
$pattern = '/\b(?i:' . implode("|", array_map(function($i) { return preg_quote(trim($i), "/"); }, $exp)) . ')\b\.?(*SKIP)(*FAIL)|\.\s*\w/u'; // добавляем модификатор u, чтобы регулярка работала с многобайтными кодировками (utf-8, utf-16)
echo preg_replace_callback(
$pattern,
function($m) { // на вход поступает каждое из найденных соответствий
return mb_strtoupper($m[0]); // используем mb_ функцию, так как она работает с многобайтными кодировками
}, $text);
}
См. пример использования:
upper_letter('Я охотник. живу в лесу.и мне комфортно и т.п');
// => Я охотник. Живу в лесу.И мне комфортно и т.п
upper_letter('См. тут. я читал и др. произведения. в 2003 г. никто об этом не знал. и т.д. и т.п');
// => См. тут. Я читал и др. произведения. В 2003 г. никто об этом не знал. И т.д. и т.п
function i_ucfirst($str){
$str = explode(' ', $str);
foreach($str as &$val){
$fstr = $val;
if(!preg_match('/\w{1}\./', $fstr)){
$fc = mb_strtoupper(mb_substr($fstr, 0, 1));
$val = $fc.mb_substr($fstr, 1);
};
};
return implode(' ', $str);
};
$foo = 'привет буфет ёпт и.т.д - и.т.п';
$foo = i_ucfirst($foo);
echo $foo
;
Вернёт Привет Буфет Ёпт и.т.д - и.т.п
Выражение данного случая '/\w{1}./' можно дополнить другими символами '/\w{1}[.,:!]/'
Например сокращённые слова будут через запятую или двоеточие ........
Думаю это эффективнее preg_replace_callback на коротких строках :(