Skip to content

Instantly share code, notes, and snippets.

@roydejong
Last active May 1, 2022 19:38
Show Gist options
  • Save roydejong/f668ef68db9bb1b2ebdd8968de39621f to your computer and use it in GitHub Desktop.
Save roydejong/f668ef68db9bb1b2ebdd8968de39621f to your computer and use it in GitHub Desktop.
PHP: Parse raw input as a float, with best guess for the decimal character (dot or comma). Useful if you do not know original locale or when you are processing user input.
<?php
function parseFloatGuess($rawValue) {
if (!$rawValue) {
return 0;
}
$lastCommaPosition = strrpos($rawValue, ',');
$lastDotPosition = strrpos($rawValue, '.');
// Special case: Neither present
if ($lastDotPosition === false && $lastCommaPosition === false) {
return floatval($rawValue);
}
// Special case: Comma is at index zero (e.g. ",123" same as ".123" or "0.123")
if ($lastCommaPosition === 0 && $lastDotPosition === false) {
$rawValue = str_replace(',', '.', $rawValue);
return floatval($rawValue);
}
// Guess what decimal separator we are using, based on which char we see last
// For example, a string formatted as "123,456.00" has a dot last, so we'll guess US dot
// Another example, a string formatted as "123.456,00" has a comma last, so we'll guess EU comma
// But a string like "123,456" is rather ambiguous and we're also forced to guess EU comma dec
$decimalChar = ($lastCommaPosition > $lastDotPosition ? ',' : '.');
$thousandsChar = ($decimalChar === '.' ? ',' : '.');
// Special guess: If there's more than one type of a char, it's probably our thousands sep
// e.g. we should probably interpret "1,456,789" as "," being the thousands separator
if (substr_count($rawValue, ',') > 1) {
$decimalChar = '.';
$thousandsChar = ',';
} else if (substr_count($rawValue, '.') > 1) {
$decimalChar = ',';
$thousandsChar = '.';
}
// Either way, dispose of what we think is our thousands char, and change to dot decimal char
$rawValue = str_replace($thousandsChar, '', $rawValue);
$rawValue = str_replace($decimalChar, '.', $rawValue);
return floatval($rawValue);
}
var_dump(parseFloatGuess("0")); // int(0)
var_dump(parseFloatGuess("0.123")); // double(0.123)
var_dump(parseFloatGuess("0,123")); // double(0.123)
var_dump(parseFloatGuess("1,100.12")); // double(1100.12)
var_dump(parseFloatGuess("1.100.444,12")); // double(1100444.12)
var_dump(parseFloatGuess("1,100,555")); // double(1100555)
var_dump(parseFloatGuess(".123")); // double(0.123)
var_dump(parseFloatGuess(",456")); // double(0.456)
@bozghiyy
Copy link

bozghiyy commented Apr 1, 2021

Thanks!
Great idea for solving the problem when you cannot control what decimal char you are going to get.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment