Reputation: 7226
I have a glorified ucwords
function which allows my system to optionally allow/disallow words within a string to be all caps:
function NormalizeWords($str, $disallowAllUppercase = false){
$parts = explode(' ', $str);
if($disallowAllUppercase){
$result = array_map(function($x){
return ucwords(strtolower($x));
}, $parts);
}else{
$result = array_map(function($x){
if (!(strtoupper($x) == $x)) {
return ucwords(strtolower($x));
}
return $x;
}, $parts);
}
return implode(' ', $result);
}
This function works in almost all cases. Where it fails is when a word is inside parens (or any non-alphanumeric characters I would assume).
Here are some examples:
writeme(NormalizeWords("Make An Omelette (template)", true));
writeme(NormalizeWords("make an omelette (template)", true));
writeme(NormalizeWords("Make An Omelette - template", true));
Results:
Make An Omelette (template) - wrong
Make An Omelette (template) - wrong
Make An Omelette - Template - right
Expected Results:
Make An Omelette (Template)
Make An Omelette (Template)
Make An Omelette - Template
You can see that when a word/words touch parens or other characters, the first letter doesn't get forced to ucase. How can I fix my function to do this?
Upvotes: 1
Views: 40
Reputation: 38542
One workaround is do it with simple and one liner
mb_convert_case()
function, by the way you can wrap it inside your NormalizeWords function.
<?php
$text= "Make (an) omelette (template)";
echo mb_convert_case($text, MB_CASE_TITLE, "UTF-8");
?>
WORKING DEMO: https://3v4l.org/NgX6W
Upvotes: 0
Reputation: 693
Or, you can temporarily replace the parens to unrecognizable words and then put it back after the NormalizeWords
:
$str = 'make an omelette (template)';
$str = str_ireplace('(','unrgcswzbl ',$str);
$str = str_ireplace(')','unrgcswzbl2 ',$str);
$str = NormalizeWords( $str,true);
$str = str_ireplace('unrgcswzbl ','',$str);
$str = str_ireplace('unrgcswzbl2 ','',$str);
echo $str;
Upvotes: 0
Reputation: 147216
By changing your function to use preg_split
to split the string on any non-alphabetic characters, you can extract only the words for capitalisation. By using the PREG_SPLIT_DELIM_CAPTURE
flag we retain all the non-alphabetic characters and we can then put the string back to together by using implode
with no glue:
function NormalizeWords($str, $disallowAllUppercase = false){
$parts = preg_split('/([^A-Za-z]+)/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
if($disallowAllUppercase){
$result = array_map(function($x){
return ucwords(strtolower($x));
}, $parts);
}else{
$result = array_map(function($x){
if (!(strtoupper($x) == $x)) {
return ucwords(strtolower($x));
}
return $x;
}, $parts);
}
return implode('', $result);
}
echo(NormalizeWords("Make AN Omelette (template)", false)) . PHP_EOL;
echo(NormalizeWords("make AN omelette (template)", true)) . PHP_EOL;
echo(NormalizeWords("Make An Omelette - template", true)) . PHP_EOL;
Output:
Make AN Omelette (Template)
Make An Omelette (Template)
Make An Omelette - Template
Note you can simplify your function by passing $disallowAllUppercase
to the array_map
function:
function NormalizeWords($str, $disallowAllUppercase = false){
$parts = preg_split('/([^A-Za-z]+)/', $str, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
$result = array_map(function ($x) use ($disallowAllUppercase) {
if ($disallowAllUppercase || strtoupper($x) != $x) {
return ucwords(strtolower($x));
}
return $x;
}, $parts);
return implode('', $result);
}
Upvotes: 1