Jens Törnell
Jens Törnell

Reputation: 24768

PHP convert uppercase words to lowercase, but keep ucfirst on lowercase words

An example:

THIS IS A Sentence that should be TAKEN Care of

The output should be:

This is a Sentence that should be taken Care of

Rules

Code

$string = ucfirst(strtolower($string));

Fails

It fails because the ucfirst words are not being kept.

This is a sentence that should be taken care of

Upvotes: 2

Views: 1207

Answers (5)

mickmackusa
mickmackusa

Reputation: 47894

I find preg_replace_callback() to be a direct tool for this task. Create a pattern that will capture the two required strings:

  1. The leading word
  2. Any non-leading, ALL-CAPS word

Code: (Demo)

echo preg_replace_callback(
         '~(^\pL+\b)|(\b\p{Lu}+\b)~u',
         function($m) {
             return $m[1]
                 ? mb_convert_case($m[1], MB_CASE_TITLE, 'UTF-8')
                 : mb_strtolower($m[2], 'UTF-8');
         },
         'THIS IS A Sentence that should be TAKEN Care of'
     );
// This is a Sentence that should be taken Care of

I did not test this with multibyte input strings, but I have tried to build it with multibyte characters in mind.

The custom function works like this:

  • There will always be either two or three elements in $m. If the first capture group matches the first word of the string, then there will be no $m[2]. When a non-first word is matched, then $m[2] will be populated and $m[1] will be an empty string. There is a modern flag that can be used to force that empty string to be null, but it is not advantageous in this case.
  • \pL+ means one or more of any letter (single or multi-byte)
  • \p{Lu}+ means one or more uppercase letters
  • \b is a word boundary. It is a zero-width character -- it doesn't match a character, it checks that the two consecutive characters change from a word to a non-word or vice versa.
  • My answer makes just 3 matches/replacement on the sample input string.

Upvotes: 1

FayFay
FayFay

Reputation: 1

$string='THIS IS A Sentence that should be TAKEN Care of';
$arr=explode(" ", $string);
foreach($arr as $v)
{
    $v = ucfirst(strtolower($v));
    $stry = $stry . ' ' . $v;
}
echo $stry;

Upvotes: -2

Isurendrasingh
Isurendrasingh

Reputation: 432

$str = "THIS IS A Sentence that should be TAKEN Care of";
$str_array = explode(" ", $str);
  foreach ($str_array as $testcase =>$str1) {
    //Check the first word
    if ($testcase ==0 && ctype_upper($str1)) {
      echo ucfirst(strtolower($str1))." ";
    }
    //Convert every other upercase to lowercase
    elseif( ctype_upper($str1)) {
      echo strtolower($str1)." ";
    }
    //Do nothing with lowercase
    else {
      echo $str1." ";
    }
  }

Output:


This is a Sentence that should be taken Care of

Upvotes: 1

FirstOne
FirstOne

Reputation: 6217

You can test each word for those rules:

$str = 'THIS IS A Sentence that should be TAKEN Care of';
$words = explode(' ', $str);
foreach($words as $k => $word){
    if(strtoupper($word) === $word || // first rule
           ucfirst($word) !== $word){ // second rule 
        $words[$k] = strtolower($word);
    }
}
$sentence = ucfirst(implode(' ', $words)); // third rule

Output:

This is a Sentence that should be taken Care of


A little bit of explanation:
Since you have overlapping rules, you need to individually compare them, so...

  • Break down the sentence into separate words and check each of them based on the rules;
  • If the word is UPPERCASE, turn it into lowercase; (THIS, IS, A, TAKEN)
  • If the word is ucfirst, leave it alone; (Sentence, Care)
  • If the word is NOT ucfirst, turn it into lowercase, (that, should, be, of)

Upvotes: 2

iainn
iainn

Reputation: 17417

You can break the sentence down into individual words, then apply a formatting function to each of them:

$sentence = 'THIS IS A Sentence that should be TAKEN Care of';

$words = array_map(function ($word) {
    // If the word only has its first letter capitalised, leave it alone
    if ($word === ucfirst(strtolower($word)) && $word != strtoupper($word)) {
        return $word;
    }

    // Otherwise set to all lower case
    return strtolower($word);
}, explode(' ', $sentence));

// Re-combine the sentence, and capitalise the first character
echo ucfirst(implode(' ', $words));

See https://eval.in/936462

Upvotes: 2

Related Questions