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

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

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

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

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

По поводу локалей - их и не нужно учитывать. Возьми любой онлайн-банкинг той же братинии или нашенский. ВЫВОД - локализованный, ввод - простое число с точкой. Никаких пробелов или, тем более, апострофов.
...
Рейтинг: 0 / 0
17.04.2012, 03:46:17
    #37756398
Edd.Dragon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
Хотя пробелы конечно же не проблема убрать, но сделать это можно во время воода на клиенте.
...
Рейтинг: 0 / 0
17.04.2012, 06:24:30
    #37756421
r u
r u
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
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
17.04.2012, 06:35:05
    #37756423
dresden
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
чет я о другом подумал, прочитав "парсинг денег". У нас этим правительство занимается.
...
Рейтинг: 0 / 0
17.04.2012, 06:35:31
    #37756424
Edd.Dragon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
Ну вот из-за неоднозначностей и нет смысла угадывать, когда можно указать допустимый вариант и требовать только его. В случае неоднозначности не будешь же выдавать ошибку "Сервер не смог определиться..." =)
...
Рейтинг: 0 / 0
17.04.2012, 06:35:55
    #37756425
Edd.Dragon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
dresdenчет я о другом подумал, прочитав "парсинг денег". У нас этим правительство занимается.
То граббинг, не путай ))
...
Рейтинг: 0 / 0
17.04.2012, 09:57:06
    #37756590
Alibek B
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
Если речь идет о прикладных приложениях, то обычно фильтрация, валидация и форматирование осуществляется непосредственно во время ввода данных (хотя форматирование можно делать и по потере фокуса).
А если речь идет о веб-приложении, то я бы к полю давал описание формата и проверял бы только соответствие введенных данных ожидаемому формату. Если используются клиентские скрипты, то еще бы при onexit приводил бы по возможности к ожидаемому формату (убрать пробелы, заменить десятичный разделитель).
...
Рейтинг: 0 / 0
17.04.2012, 10:13:53
    #37756621
Ренат
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
Alibek B.Если речь идет о прикладных приложениях, то обычно фильтрация, валидация и форматирование осуществляется непосредственно во время ввода данных (хотя форматирование можно делать и по потере фокуса).
А если речь идет о веб-приложении, то я бы к полю давал описание формата и проверял бы только соответствие введенных данных ожидаемому формату. Если используются клиентские скрипты, то еще бы при onexit приводил бы по возможности к ожидаемому формату (убрать пробелы, заменить десятичный разделитель).
необходимо просто через к примеру http://mmcrm.ru/?p=1793 запретить пользователям вводить что либо другое. Пусть вводит текст по маске, и им не надо будет голову ломать как денежку ввести, и вам как прогармистам не надо будет пытаться распрасить строку.
...
Рейтинг: 0 / 0
17.04.2012, 18:59:22
    #37757854
как-то так
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
угу... ещё можно отделить копейки от рублей
Код: 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
18.04.2012, 00:02:41
    #37758210
Аноним 250
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
Посмотрел как сделали парни в Альфа-Банке:
Во-первых, они не допускают присутствия в числе одновременно запятой и точки
Во-вторых, в качестве decimal separator допускается и точка и запятая
В-третьих, после разделителя допускается только 1 или 2 цифры
В-четвертых, для исключения ошибки требуется подтверждение, т.е. типа "Подтвердите сумму перевода: 170.12 usd"

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

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

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

Код: 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
18.04.2012, 01:48:33
    #37758260
Edd.Dragon
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
Аноним 250,

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

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


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

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

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



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

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

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


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

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

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

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

Вполне себе валидненькие 987 мульйонов. =)
...
Рейтинг: 0 / 0
19.04.2012, 12:37:17
    #37760786
an0nym
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
Код: 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
19.04.2012, 12:42:55
    #37760802
an0nym
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
Смысл в логику вкладывал следующий.

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

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

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

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

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

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

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

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

откройте для себя dataProvider в phpunit.
...
Рейтинг: 0 / 0
19.04.2012, 12:50:56
    #37760816
an0nym
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
и setExpectedException.
...
Рейтинг: 0 / 0
19.04.2012, 13:25:02
    #37760879
r u
r u
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
если хочется чтоб чтоб скрипт жрал все подряд:
Код: 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
19.04.2012, 13:31:16
    #37760898
an0nym
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
[PHP ] Парсинг суммы денег введенной пользователем - best practices?
r u,

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

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

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

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

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


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