WackGet
WackGet

Reputation: 2916

PHP - most elegant way to check if a string contains only a whole or half decimal number?

I thought this would be extremely simple but it turns out in PHP it's tricky to determine whether a string contains only an integer or a float which is a whole or half number.

For example, I want:

// Approved  
"0.5"
"12"  
"22.5"  
"6.0"
"1"
"0"

// Rejected  
"0.65"  
"foo19bar"  
"ten"  
"39.4"
"s12"
"0x600"

Things making it tricky:

My most succinct solution so far is this one, but I feel like there should be a better way to do this:

if (ctype_digit($rating) || (is_float($rating + 0) && fmod($rating, 0.5) == 0)) {
    if (is_numeric($rating)) {
        echo "Approved";
    }
}

Upvotes: 2

Views: 262

Answers (2)

Havenard
Havenard

Reputation: 27864

<?php

$test = [
    "0.5",
    "12",  
    "22.5",  
    "6.0",
    "1",
    "0",
    "0.65",
    "foo19bar",
    "ten",
    "39.4",
    "s12",
    "0x600",
];

foreach ($test as $number)
    if ((string)((int)((double)$number * 2) / 2) == $number)
        echo "Approved $number\n";
    else
        echo "Rejected $number\n";

Outputs:

Approved 0.5
Approved 12
Approved 22.5
Approved 6.0
Approved 1
Approved 0
Rejected 0.65
Rejected foo19bar
Rejected ten
Rejected 39.4
Rejected s12
Rejected 0x600

Upvotes: 4

Nick
Nick

Reputation: 147166

Why not just use a regex e.g.

if (preg_match('/^\d+(\.[05]0*)?$/', $rating)) echo "\"$rating\": Approved\n";

This one will allow trailing 0s after a number so 4.50 will pass as does 4.5. If you don't want that just remove the 0* part of it.

e.g.

$ratings = array(
"0.5",
"12"  ,
"22.5" , 
"6.0",
"1",
"0",
"4.5",
"3.500",
"1.00",
"0.65"  ,
"foo19bar"  ,
"ten"  ,
"39.4",
"s12",
"0x600"
    );
foreach ($ratings as $rating) {
    echo "\"$rating\": " . (preg_match('/^\d+(\.[05]0*)?$/', $rating) ? "Approved\n" : "Rejected\n");
}

Output:

"0.5": Approved
"12": Approved
"22.5": Approved
"6.0": Approved
"1": Approved
"0": Approved
"4.5": Approved
"3.500": Approved
"1.00": Approved
"0.65": Rejected
"foo19bar": Rejected
"ten": Rejected
"39.4": Rejected
"s12": Rejected
"0x600": Rejected

Upvotes: 2

Related Questions