odd_duck
odd_duck

Reputation: 4101

PHP - Capitalise first character of each word expect certain words

I have a batch of strings like so:

tHe iPad hAS gONE ouT of STOCK
PoWER uP YOur iPhone
wHAT moDEL is YOUR aPPLE iPHOne

I want to capitalise the first character of each word and have the remaining characters lowercase - except any references of iPhone or iPad. As in:

By using:

ucwords(strtolower($string));

This can do most of what is needed but obviously also does it on iPadand iPhone:

The Ipad Has Gone Out Of Stock
Power Up Your Iphone
What Model Is Your Apple Iphone

How can I do achieve the below:

The iPad Has Gone Out Of Stock
Power Up Your iPhone
What Model Is Your Apple iPhone

Upvotes: 5

Views: 14162

Answers (6)

Sandeep DiL
Sandeep DiL

Reputation: 1

This will might help you.. i write this code for my use and its working perfectly for me...

<?php
function strtocap($arg){
    $finalStr = array();

    $argX = explode(" ",$arg);
    if(is_array($argX)){
        foreach($argX as $v){
            $finalStr[] = ucfirst(strtolower($v));
        }
    }
return implode(" ",$finalStr);
}

$str = "Your unForMated StrInG";
echo strtocap($str);
?>

Upvotes: 0

syck
syck

Reputation: 3029

A more generic solution:

<?php

$text = <<<END_TEXT
PoWER uP YOur iPhone
tHe iPad hAS gONE ouT of STOCK 
wHAT moDEL is YOUR aPPLE iPHOne
END_TEXT;

$text = preg_replace(array('/iphone/i', '/iPad/i'), array('iPhone', 'iPad'), $text);
$text = preg_replace_callback('/(\b(?!iPad|iPhone)[a-zA-Z0-9]+)/', 
     function ($match) { return ucfirst(strtolower($match[1])); }, $text);

echo $text;

Demo

Uses a negative lookahead in the regex to exclude the listed words from matching and manipulates the others via a callback to an anonymous function. That way, you can do any kind of manipulation, for example reversing the string.

Upvotes: 0

mickmackusa
mickmackusa

Reputation: 47764

Best practice is to call strtolower() on the input string straight away (syck's answer doesn't do this).

I'll offer a pure regex solution that will appropriately target your ipad and iphone words and capitalize their seconds letter while capitalizing the first letter of all other words.

Code: (PHP Demo) (Pattern Demo)

$strings = [
    "tHe iPad hAS gONE ouT of STOCK
PoWER uP YOur iPhone
wHAT moDEL is YOUR aPPLE iPHOne",           // OP's input string
    "fly the chopper to the helipad.
an audiphone is a type of hearing aid
consisting of a diaphragm that, when
placed against the upper teeth, conveys
sound vibrations to the inner ear"          // some gotcha strings in this element
];

foreach ($strings as $string) {
    echo preg_replace_callback('~\bi\K(?:pad|phone)\b|[a-z]+~', function($m) {return ucfirst($m[0]);}, strtolower($string));
    echo "\n---\n";
}

Output:

The iPad Has Gone Out Of Stock
Power Up Your iPhone
What Model Is Your Apple iPhone
---
Fly The Chopper To The Helipad.
An Audiphone Is A Type Of Hearing Aid
Consisting Of A Diaphragm That, When
Placed Against The Upper Teeth, Conveys
Sound Vibrations To The Inner Ear
---

Probably the only parts to mention about the regex pattern is that \K means "restart the fullstring match" or in other words "consume and forget the previous character(s) in the current match".

Upvotes: 1

Happy
Happy

Reputation: 48

Instead of having to write the lower- and uppercase version of each word you want to exclude respectively and thus having to write them twice, you could only define them once in an array and using str_ireplace instead of str_replace like this:

$string = "tHe IPHONE and iPad hAS gONE ouT of STOCK";

$excludedWords = array(
    "iPad",
    "iPhone"
);

echo str_ireplace($excludedWords, $excludedWords, ucwords(strtolower($string)));

Which would result in

The iPhone And iPad Has Gone Out Of Stock

This would then replace all occurrences of these words with the version you've defined in the array.

Edit:

Keep in mind that using this, words like "shipadvertise" would be replaced with "shiPadvertise". If you want to prevent this, you could use a more advanced solution using regular expressions:

$string = "tHe IPHONE and shipadvertise iPad hAS gONE ouT of STOCK";

$excludedWords = array(
    "iPad",
    "iPhone"
);
$excludedWordsReg = array_map(function($a) { return '/(?<=[\s\t\r\n\f\v])'.preg_quote($a).'/i'; }, $excludedWords);

echo preg_replace($excludedWordsReg, $excludedWords, ucwords(strtolower($string)));

This would then correctly resolve into

The iPhone And Shipadvertise iPad Has Gone Out Of Stock

I've used the delimiters for determining words ucwords uses by default.

Upvotes: 2

Yazid Erman
Yazid Erman

Reputation: 1186

As you know the specific words, and they are limited, why don't you just revert them back after the total capitalization, just as following

$string = ucwords(strtolower($string));
$string = str_replace("Ipad","iPad", $string);
$string = str_replace ("Iphone","iPhone", $string);

Upvotes: 2

Don&#39;t Panic
Don&#39;t Panic

Reputation: 41810

You can use str_replace for this. If you use arrays for the first two arguments, you can define a set of words and replacements:

echo str_replace(['Ipad', 'Iphone'], ['iPad', 'iPhone'], ucwords(strtolower($string)));

From the documentation:

If search and replace are arrays, then str_replace() takes a value from each array and uses them to search and replace on subject.

Upvotes: 4

Related Questions