#c# #regex #winforms
Вопрос:
У меня есть текстовое поле с обработчиком LostFocus
событий, который вызывает метод, форматирующий строку чисел в текстовом поле в числовой формат. Например, 123456,78
возвращает 123 456,78
.
Если я вместо этого начну с 123 45
правильного возврата 12 345,00
.
Однако, если я сначала наберу 123456,78
, и он правильно вернется 123 456,78
, а затем удалю последние четыре символа в текстовом поле с помощью клавиши backspace, т. Е. Удалю 6,78
, нажав четыре раза на кнопку backspace, это не сработает. Он просто остается 123 45
в текстовом поле.
Однако, если я выделю весь текст в текстовом поле и вставлю 123 45
его, он вернется 12 345,00
правильно.
Когда я отлаживаю, шагая по одной строке за раз , я вижу, что аргумент метода amountIn
правильно сохраняет строку 123 45
, как при использовании клавиш backspace, так и при выборе и вставке. Однако Regex.IsMatch()
возвращается false
, когда я использую backspace и true
когда я выбираю и вставляю. Следовательно, я считаю, что обратное пространство оставляет в строке какой-то артефакт, который не виден во время отладки, но распознается IsMatch()
методом. Вот мой метод:
private void txtAmount_LostFocus(object sender, EventArgs e)
{
txtAmount.Text = ReformatAmount(txtAmount.Text);
}
public static string ReformatAmount(string amountIn)
{
string amountOut;
if (Regex.IsMatch(amountIn, @"^[0-9 ,.] $"))
{
amountOut = Regex.Replace(amountIn, "[. ]", "");
amountOut = Convert.ToDecimal(amountOut).ToString("N");
return amountOut;
}
else
{
amountOut = amountIn;
return amountOut;
}
}
Комментарии:
1. Вы рассматривали возможность использования чего-то подобного
decimal.TryParse
вместо этого?2. Флайдог, я попробовал твой метод, и он тоже сработал. Отличное решение! Спасибо
Ответ №1:
Разделитель CultureInfo.NumberFormat.numbergroup в Швеции-это неразрывный пробел, символ 0xA0
(160), а не символ 0x20
(32), пробел, обычно используемый для разделения, например, слов.
Вы можете видеть это лучше, написав:
var cultureSE = CultureInfo.GetCultureInfo("se-SE");
string hexChar = ((int)cultureSE.NumberFormat.NumberGroupSeparator[0]).ToString("X2");
hexChar
будет "A0"
.
Используемое регулярное ^[0-9 ,.] $
выражение не учитывает это, оно учитывает только символ 0x20
.
Вы можете изменить его на просто [0-9 ,.]
игнорировать, но, вероятно, вы захотите использовать s
вместо этого, он также будет соответствовать всем символам пробела в Юникоде, включая неразрывные символы пробела, как символ 0xA0
.
См. Также: Классы символов в регулярных выражениях
Затем выражение может быть изменено в:
if (Regex.IsMatch(amountIn, @"^[0-9s,.] $"))
{
// Convert to a culture-specific number representation
}
Комментарии:
1. Потрясающе! Спасибо!
Ответ №2:
Нет необходимости в регулярных выражениях:
string[] nums = new[]
{
"123456,78",
"123 456,78",
"6,78",
"123 45"
};
foreach (var num in nums)
{
if (Decimal.TryParse(num, NumberStyles.Any, null, out decimal result))
{
// Number successfully parsed:
Console.WriteLine($"{result:N2}");
}
else
{
// Parsing error here
Console.WriteLine($"Could not parse: '{num}'");
}
}
Выход:
123 456,78
123 456,78
6,78
12 345,00
Комментарии:
1. Поскольку вы анализируете пользовательский ввод (который часто включает опечатки с жирным пальцем ), рассмотрите
decimal.TryParse
вместо.Parse
2. Это очевидно, но сделает это более понятным ))