Разбор строки non-ascii (unicode) в качестве целого в .NET.
У меня есть строка, содержащая число в формате без ascii, например. unicode BENGALI DIGIT ONE (U + 09E7): "১"
Как разобрать это как целое число в .NET?
Примечание. Я попытался использовать int.Parse()
, определяя формат культуры bengali с помощью "bn-BD" в качестве IFormatProvider. Не работает.
Ответы
Ответ 1
Вы можете создать новую строку, которая совпадает с старой строкой, за исключением того, что нативные цифры заменяются латинскими десятичными цифрами. Это можно сделать надежно, пройдя через символы и проверив значение char.IsDigit(char)
. Если эта функция возвращает true, то преобразуйте ее с помощью char.GetNumericValue(char).ToString()
.
Вот так:
static class DigitHelper
{
public static string ConvertNativeDigits(this string text)
{
if (text == null)
return null;
if (text.Length == 0)
return string.Empty;
StringBuilder sb = new StringBuilder();
foreach (char character in text)
{
if (char.IsDigit(character))
sb.Append(char.GetNumericValue(character));
else
sb.Append(character);
}
return sb.ToString();
}
}
int value = int.Parse(bengaliNumber.ConvertNativeDigits());
Ответ 2
Похоже, что это невозможно с использованием встроенных функций:
Единственные Unicode-цифры, которые .NET Framework анализирует как десятичные знаки, - это цифры ASCII от 0 до 9, заданные значениями кода U + 0030 через U + 0039.
...
Попытка разобрать значения кода Unicode для цифр Fullwidth, цифр на арабском языке и бенгальских цифр завершается с ошибкой и генерирует исключение.
(акцент мой)
Очень странно, что CultureInfo("bn-BD").NumberFormat.NativeDigits
содержит их.
Ответ 3
Найдя этот вопрос, ища аналогичный ответ, но не найдя ответа, который был полностью сопоставлен с тем, что мне нужно, я написал следующее, поскольку он хорошо относится к знакам, и быстрее сбой, если задана очень длинная строка. Однако он не игнорирует любые группирующие символы, такие как ,
, '
, ’
, хотя это может быть легко добавлено, если кто-то хочет (я этого не делал):
public static int ParseIntInternational(this string str)
{
int result = 0;
bool neg = false;
bool seekingSign = true; // Accept sign at beginning only.
bool done = false; // Accept whitespace at beginning end or between sign and number.
// If we see whitespace once we've seen a number, we're "done" and
// further digits should fail.
for(int i = 0; i != str.Length; ++i)
{
if(char.IsWhiteSpace(str, i))
{
if(!seekingSign)
done = true;
}
else if(char.IsDigit(str, i))
{
if(done)
throw new FormatException();
seekingSign = false;
result = checked(result * 10 + (int)char.GetNumericValue(str, i));
}
else if(seekingSign)
switch(str[i])
{
case '﬩': case '+':
//do nothing: Sign unchanged.
break;
case '-': case '−':
neg = !neg;
break;
default:
throw new FormatException();
}
else throw new FormatException();
}
if(seekingSign)
throw new FormatException();
return neg ? -result : result;
}