Разбор строки 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;
}