powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / PHP, Perl, Python [игнор отключен] [закрыт для гостей] / [PHP ] Парсинг суммы денег введенной пользователем - best practices?
33 сообщений из 33, показаны все 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
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37760943
an0nym
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
r uну и пусть)
тут значащими являются только цифры и ЛЮБОЙ разделитель целой и дробной части. остальное мусор)
можно же потом переспросить юзера, эту сумму он имел в виду или нет. а ваш вариант ошибочную вообще не пропустит, тоесть даже исправлять юзеру отдать нечего.В моём случае переспрашивать юзера не надо. В вашем случае надо, даже если он ввёл 1234.56 - или надо городить два метода потипу isObviousNumeric и isGuessableNumeric. r up.s. ваш вариант кстати .08 не съест, хотя так вводить копейки считается вполне допустимымЭто легко исправляется. Лучше приведите контр-пример, когда мой метод откровенную чушь пропустит - вот тут я как раз в себе не уверен и жду критики. Самому интересно.
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37760992
Фотография r u
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
an0nymВ моём случае переспрашивать юзера не надо.
как это ненадо? если ваша функция не может переварить какойлибо формат, то явно придется спросить еще раз? а может и не раз

an0nymЭто легко исправляется.

а когда исправится тогда возможно и другие баги всплывут)
чем сложнее реализация тем больше в ней ошибок

an0nymЛучше приведите контр-пример, когда мой метод откровенную чушь пропустит - вот тут я как раз в себе не уверен и жду критики. Самому интересно.
понимаете, мы с вами по разному подошли к решению. вы пытаетесь склонить юзера к принятому у вас формату, если юзер нехочет(или непонимает) что нужно ввести - то все тупик - функция ваша просто ничего не пропустит.

я же пошел по пути другому. мы ждем от юзера сумму - вот пусть ее и вводит, с ЛЮБЫМИ разделителями. он может даже не сам ее набирать а скопировать с ДРУГИХ ИСТОЧНИКОВ (с другого сайта, программы и т.д.). , а там может попасться любой мусор. и моя функция нормализует то что он ввел. может комуто пригодится.
по такому принципу я писал парсер для даты, при импорте данных с других систем в мою. формат везде отличался то dd/mm/yyyy то yy.mm.dd то еще как. заставить я никого не мог, формат мог меняться без предупреждения меня. и приходилось ЕСТЬ все эти форматы. а чтоб не парится с каждым я сделал подобную функцию. которая сама определяла в каком формате дата и нормализовывала ее в нужный мне. валилась она только когда ну уж совсем никак нельзя было интерпретировать корректно дату.

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

кстати вот:
var_dump(parse_number('1234')); // NULL
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37761039
an0nym
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
r u,

(?P<ts>[ ,.]?)
? надо вынести за скобки
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37761931
Edd.Dragon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
r uну и пусть)
Вот было бы забавно, если б так думали разработчики онлайн-банкингов. Вводишь по-своему, оно парсит по-своему - финансовые операции, чо!
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37762215
Фотография r u
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Edd.Dragonr uну и пусть)
Вот было бы забавно, если б так думали разработчики онлайн-банкингов. Вводишь по-своему, оно парсит по-своему - финансовые операции, чо!
в случаях связанных с фин.операциями все равно всегда спрашивают подтверждения, показывая при этом все реквизиты платежа и сумму. так что все в рамках концепции)
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37762394
Edd.Dragon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
r uEdd.Dragonпропущено...

Вот было бы забавно, если б так думали разработчики онлайн-банкингов. Вводишь по-своему, оно парсит по-своему - финансовые операции, чо!
в случаях связанных с фин.операциями все равно всегда спрашивают подтверждения, показывая при этом все реквизиты платежа и сумму. так что все в рамках концепции)
Ну меж двумя банкингами, один из которых возле поля ввода пишет "Вводите сумму как хотите - разберемся", а другой "Введите число в виде 123456 или 123456.78", я пожалуй выберу второй. А то может у первого вся работа построена по принципу "делай как в голову взбредет - там разберемся", то ну его от греха подальше...
...
Рейтинг: 0 / 0
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
    #37762400
Edd.Dragon
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
На самом деле часто не пишут ничего, потом шлют запрос на сервер (не проверяя и не корректируя шаблон на клиенте по месту и ничего не подсказывая), после чего выдают отлуп, что мол запрос некоректен. Вот сиди и угадывай. А в результате окажется, что не раз вводил правильно, просто где-то глюк и суммы с копейками не проходят.

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


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