powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PHP, Perl, Python [игнор отключен] [закрыт для гостей] / [PHP ] Парсинг суммы денег введенной пользователем - best practices?
25 сообщений из 33, страница 1 из 2
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37756392
Аноним 250
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Здравствуйте,

Допустим, пользователь вводит сумму в поле формы, и нам нужно правильно отпарсить введенное им значение. А пользователь может ввести:
1234,56
1234.56
1.234,56
1,234.56

Не надо меня отправлять по ссылке на класс NumberFormatter или типа того, потому что локаль пользователя неизвестна. Или даже если известна, то это ничего не гарантирует. Русский пользователь из США может вводить сумму по-привычке по-русски. А может вообще использовать точку или запятую в зависимости от настроения или фазы луны.

Как принято решать данную проблему?
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37756397
Edd.Dragon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А кто-то прописью введет - не писать же парсер на всех языках.

Указать рядом пример, как следует вводить и когда число не соответствует - выдавать ошибку. А не пытаться предусмотреть все фантазии и опечатки пользователя.

По поводу локалей - их и не нужно учитывать. Возьми любой онлайн-банкинг той же братинии или нашенский. ВЫВОД - локализованный, ввод - простое число с точкой. Никаких пробелов или, тем более, апострофов.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37756398
Edd.Dragon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хотя пробелы конечно же не проблема убрать, но сделать это можно во время воода на клиенте.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37756421
Фотография r u
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Edd.Dragon,

если заранее определить какие случаи ввода мы хотим обрабатывать то можно сделать чтото типа:
Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
function strToMoney($in) {
	$in = strtr(trim($in), array(','=>'.'));
	return (float)preg_replace("/([\d.']+?)(\.\d{1,2})?$/e", "str_replace('.','','\\1').'\\2'", $in);
}

$a = array(' 0 ','4','88','123','234.0',' 999,99 ', '1234,56','1234.56','1.234,06','1,234.56','1,345,456.00','9.567.456,34');
$b = array_map('strToMoney',$a);

echo '<pre>';
print_r($b);


но тут есть неоднозначности все равно на которые даже человек не ответит точно.
например ввели
123,679 - это 123.679 или 123679.00 ?
и т.д.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37756423
dresden
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
чет я о другом подумал, прочитав "парсинг денег". У нас этим правительство занимается.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37756424
Edd.Dragon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну вот из-за неоднозначностей и нет смысла угадывать, когда можно указать допустимый вариант и требовать только его. В случае неоднозначности не будешь же выдавать ошибку "Сервер не смог определиться..." =)
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37756425
Edd.Dragon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
dresdenчет я о другом подумал, прочитав "парсинг денег". У нас этим правительство занимается.
То граббинг, не путай ))
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37756590
Alibek B
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если речь идет о прикладных приложениях, то обычно фильтрация, валидация и форматирование осуществляется непосредственно во время ввода данных (хотя форматирование можно делать и по потере фокуса).
А если речь идет о веб-приложении, то я бы к полю давал описание формата и проверял бы только соответствие введенных данных ожидаемому формату. Если используются клиентские скрипты, то еще бы при onexit приводил бы по возможности к ожидаемому формату (убрать пробелы, заменить десятичный разделитель).
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37756621
Фотография Ренат
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Alibek B.Если речь идет о прикладных приложениях, то обычно фильтрация, валидация и форматирование осуществляется непосредственно во время ввода данных (хотя форматирование можно делать и по потере фокуса).
А если речь идет о веб-приложении, то я бы к полю давал описание формата и проверял бы только соответствие введенных данных ожидаемому формату. Если используются клиентские скрипты, то еще бы при onexit приводил бы по возможности к ожидаемому формату (убрать пробелы, заменить десятичный разделитель).
необходимо просто через к примеру http://mmcrm.ru/?p=1793 запретить пользователям вводить что либо другое. Пусть вводит текст по маске, и им не надо будет голову ломать как денежку ввести, и вам как прогармистам не надо будет пытаться распрасить строку.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37757854
как-то так
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
угу... ещё можно отделить копейки от рублей
Код: php
1.
2.
<input type="text" name="currency[whole]" value="0" maxlength="5" />
<input type="text" name="currency[balance]" value="00" maxlength="2" />


на сервере просто склеить с нужным разделителем - клиенту и голову ломать не нужно, что вставлять .\, ?
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37758210
Аноним 250
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Посмотрел как сделали парни в Альфа-Банке:
Во-первых, они не допускают присутствия в числе одновременно запятой и точки
Во-вторых, в качестве decimal separator допускается и точка и запятая
В-третьих, после разделителя допускается только 1 или 2 цифры
В-четвертых, для исключения ошибки требуется подтверждение, т.е. типа "Подтвердите сумму перевода: 170.12 usd"

По-моему, вполне неплохо.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37758212
Edd.Dragon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вполне

авторВо-первых, они не допускают присутствия в числе одновременно запятой и точки
А точнее, двух вхождений разделителя. Две точки или две запятые тоже, вроде, не к месту ;)
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37758218
Аноним 250
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Edd.DragonВполне

авторВо-первых, они не допускают присутствия в числе одновременно запятой и точки
А точнее, двух вхождений разделителя. Две точки или две запятые тоже, вроде, не к месту ;)
Да, действительно, такой тест я пропустил :)
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37758249
Аноним 250
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вот накатал на скорую руку:

Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
class MoneyParser
{
	/**
	 * Returns a converted float value or null if $value is not a correct money value.
	 *
	 * @static
	 * @param string $value
	 * @return float|null
	 */
	public static function tryParse($value)
	{
		$correctValuePattern = '/^\d+([.,]\d{1,2})?$/';
		$value = trim($value);
		$valueIsCorrect = preg_match($correctValuePattern, $value);
		return $valueIsCorrect ? (float)str_replace(',', '.', $value) : null;
	}

	/**
	 * Returns a converted float value or throws an exception if $value is not a correct money value.
	 *
	 * @static
	 * @param string $value
	 * @return float
	 * @throws Exception
	 */
	public static function parse($value)
	{
		$parsed = self::tryParse($value);
		if($parsed === null)
			throw new Exception('Wrong money value.');

		return $parsed;
	}
}

class MoneyParserTests extends PHPUnit_Framework_TestCase
{
	private $testDataCorrect = array(
		'1234.56' 	=> 1234.56,
		'1234.5'		=> 1234.5,
		'1234'			=> 1234,
		'1234,56'		=> 1234.56,
		'1234,5'		=> 1234.5,
		'0,5'				=> 0.5,
		'0.5'				=> 0.5,
		'0'					=> 0,
		'0,0'				=> 0,
		'0.00'			=> 0,
		' 123   '		=> 123,
		' 123.01	'	=> 123.01
	);

	private $testDataToFail = array(
		'123.01.01',
		'987,123,13',
		'987,123,134',
		',1',
		'1,',
		'1.',
		'123.123,12',
		'123,456.12',
		'',
		' ',
		'true',
		null,
		'123 usd',
		'$123'
		);

	public function testTryParse()
	{
		foreach($this->testDataCorrect as $str => $expectedFloatValue)
			$this->assertEquals($expectedFloatValue, MoneyParser::tryParse($str));

		foreach($this->testDataToFail as $str)
			$this->assertNull(MoneyParser::tryParse($str));
	}

	public function testParse()
	{
		foreach($this->testDataCorrect as $str => $expectedFloatValue)
			$this->assertEquals($expectedFloatValue, MoneyParser::parse($str));

		foreach($this->testDataToFail as $str)
		{
			try
			{
				MoneyParser::parse($str);
				$this->fail('Exception has to be thrown.');
			}
			catch(Exception $ex) { }
		}
	}
}
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37758260
Edd.Dragon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Аноним 250,

Серверу лучше ожидать стандартного вида, проверяемого одной лишь регуляркой:

Код: php
1.
^\d+(\.\d\d)?$


с точностью до пробелов перед и после, если перед проверкой делать trim()

Т.е. либо только ряд цифр (цело число), либо цифры-точка-цифра-цифра (с копейками).

Код: php
1.
2.
$sum = trim(......);
if(preg_match('/^\d+(\.\d\d)?$/') == 0) // прекращаем разговор



Вот и вся проверка на сервере. При чем, такая строка является валидным числом как для php, так и для sql-запросов.
Ну можно еще серверу разрешить принимать как запятую, так и точку. Тогда просто после трима, перед валидацией меняем запятую на точку.

А вот на клиенте реализуй любые желаемые финты. Запятую? Не проблема. Перед отправкой заменишь на точку. Пробелы между цифрами? Аналогично, регуляркой удалишь.

И точно так же, при нажатии "Отправить" проверяешь регуляркой на соответствие ДОПУСТИМОМУ шаблону (или нескольким). Не допустимые комбинации сами собой отпадают любые. Впрочем, хочешь - можешь и более разветвленную логику реализовать, но это мартышкин труд, честно говоря.


А все те 100 строк серверного кода ни к чему.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37758262
Edd.Dragon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
if(preg_match('/^\d+(\.\d\d)?$/') == 0)

Код: php
1.
if(preg_match('/^\d+(\.\d\d)?$/', $sum) == 0)
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37758263
Edd.Dragon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Можно и такую регулярку, чтобы допускать и одну копеечную цифру:

Код: php
1.
^\d+(\.\d\d?)?$
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37760348
Anjey aka PM
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Аноним 250,

а почему это вот это фэйл: '987,123,134'

Вполне себе валидненькие 987 мульйонов. =)
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37760786
an0nym
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
<?php
function parse_number($input)
{
    $output = null;
    $input = trim($input);
    if (preg_match('/^\d{1,3}(?:(?P<ts>[ ,.]?)\d{3})?(?:(?P=ts)\d{3})*(?!(?P=ts))(?:(?P<fs>[,.])\d*)?$/', $input, $match))
    {
        $replacements = array();
        if (isset($match['ts']) and $match['ts'])
        {
            $replacements[$match['ts']] = '';
        }
        if (isset($match['fs']) and '.' !== $match['fs'])
        {
            $replacements[$match['fs']] = '.';
        }
        $output = strtr($input, $replacements);
        $output = rtrim($output, '.');
    }
    return $output;
}

var_dump(parse_number($argv[1]));
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37760802
an0nym
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Смысл в логику вкладывал следующий.

Разделитель тысяч всегда стоит после 3 цифр. Если кто-то написал 1,11,111 - это уже его проблемы - с местными порядками написания чисел, afaik, это нигде не связано.

Разделитель тысяч и десятичной части не могут совпадать.

Разделитель десятичной части не может повторяться, в отличии от разделителя тысяч.

Разделитель тысяч может отсутствовать.

Проверяем, что входная строка соответствует этим правилам. Вычленяем во время проверки из неё разделитель тысяч и разделитель десятичной части (может не быть ни того, ни того).

Удаляем из строки разделители тысяч, если они есть, так как представление числа (int/float) в php без них.

Заменяем разделитель десятичной части на точку, если он уже не точка, по тем же причинам.

Если десятичных знаков не передано, удаляем с конца разделитель десятичной части.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37760814
an0nym
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Аноним 250,

откройте для себя dataProvider в phpunit.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37760816
an0nym
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
и setExpectedException.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37760879
Фотография r u
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
если хочется чтоб чтоб скрипт жрал все подряд:
Код: php
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
function strToMoney($in) {
	$in = preg_replace("/[.,' ]/",",",trim($in));		// заменяем любые разделители(нецифры) на ,
	$in = preg_replace("/(,)(\d{1,2})$/",".$2",$in);	// десятичные(если есть) отделяем точкой
	return (float)str_replace(',','',$in);			// удаляем мусор
}

$inputSumms = array(' 0 ','.9','.87','4','88','123','234.0',' 999,99 ', '12.34,56','.1234.56','1.234,06','1,234.56','1,345,456.00','9,5,67.456,34');
$validVals= array_map('strToMoney', $inputSumms);

echo '<pre>';
print_r($inputSumms);
print_r($validVals);
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37760898
an0nym
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
r u,

не всё подряд, а адекватное всё подряд.

Ваш сожрёт 11 1.',1'12 и не подавится.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37760921
Фотография r u
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
an0nymr u,

не всё подряд, а адекватное всё подряд.

Ваш сожрёт 11 1.',1'12 и не подавится.
ну и пусть)
тут значащими являются только цифры и ЛЮБОЙ разделитель целой и дробной части. остальное мусор)
можно же потом переспросить юзера, эту сумму он имел в виду или нет. а ваш вариант ошибочную вообще не пропустит, тоесть даже исправлять юзеру отдать нечего.

p.s. ваш вариант кстати .08 не съест, хотя так вводить копейки считается вполне допустимым
...
Рейтинг: 0 / 0
25 сообщений из 33, страница 1 из 2
Форумы / PHP, Perl, Python [игнор отключен] [закрыт для гостей] / [PHP ] Парсинг суммы денег введенной пользователем - best practices?
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]