2010-07-08 2 views
5

В среде, в которой моя программа будет работать, люди используют «,» и «.». как десятичные разделители случайным образом на ПК с «,» и «.». сепараторы.Универсальный синтаксический анализ строк в поплавке

Как бы вы реализовали такую ​​функцию floatparse (string)?

Я попытался это один:

try 
    { 
     d = float.Parse(s); 
    } 
    catch 
    { 
     try 
     { 
      d = float.Parse(s.Replace(".", ",")); 
     } 
     catch 
     { 
      d = float.Parse(s.Replace(",", ".")); 
     } 
    } 

Это не работает. И когда я отлаживаю, получается, что он неправильно разбирает это в первый раз, думая, что «.» является разделителем для тысяч (например, 100.000.000,0).

Я нуб в C#, так что надеюсь, есть менее усложненное решение тогда :-)

NB: Люди, идущие использовать как «» и «,» на ПК с различными настройками разделителя.

+0

Что бы вы хотели, чтобы кто-то написал 100.000.00? Вы хотите, чтобы с ним обращались как 10000.00 или 100.0000? Или это не номер? –

+0

эх, винт более одного символа без цифр! – Halst

+0

Более гибкое решение может заключаться в том, чтобы позволить пользователю выбирать свою культуру. Таким образом, все числа и даты могут быть отформатированы автоматически до того, к чему они привыкли. И ToString(), и Format() будут работать, не пытаясь «взломать» его. Или ИТ-специалисты исправят компьютеры, чтобы культура была правильно настроена ... – Greg

ответ

9

Если вы уверены, что никто не использует тысячу сепараторов, вы можете заменить первый:

string s = "1,23"; // or s = "1.23"; 

s = s.Replace(',', '.'); 
double d = double.Parse(s, CultureInfo.InvariantCulture); 

Общая картина будет:

  • первой попытки санировать и нормализуют. Подобно Replace (otherChar, myChar).
  • попытайтесь обнаружить формат, возможно, используя RegEx, и используйте целевое преобразование. Как подсчет. и, чтобы угадать, используются ли тысячи разделителей.
  • Попробуйте несколько форматов в порядке, с TryParse. Do нет использование исключений для этого.
+0

, как я понимаю, в инвариантном сепараторе культуры всегда есть. ? – Halst

+0

hm, VS2008EE sais 'CultureInfo' не существует в текущем контексте ... мне нужно как-то объявить его? – Halst

+0

Вам необходимо импортировать System.Globalization –

1

Я бы коснуться как этот

float ConvertToFloat(string value) 
{ 
    float result; 

    var converted = float.TryParse(value, out result); 

    if (converted) return result; 

    converted = float.TryParse(value.Replace(".", ",")), 
           out result); 

    if (converted) return result; 

    return float.NaN; 
} 

В этом случае следующее будет возвращать правильные данные

 Console.WriteLine(ConvertToFloat("10.10").ToString()); 
     Console.WriteLine(ConvertToFloat("11,0").ToString()); 
     Console.WriteLine(ConvertToFloat("12").ToString()); 
     Console.WriteLine(ConvertToFloat("1 . 10").ToString()); 

Возвраты

10,1 
11 
12 
NaN 

В этом случае, если ему это невозможно чтобы преобразовать его, вы, по крайней мере, знаете, что это не число. Это безопасный способ конвертировать.

Вы можете также использовать следующую перегрузку

float.TryParse(value, 
      NumberStyles.Currency, 
      CultureInfo.CurrentCulture, 
      out result) 

На этом тест-код:

Console.WriteLine(ConvertToFloat("10,10").ToString()); 
Console.WriteLine(ConvertToFloat("11,0").ToString()); 
Console.WriteLine(ConvertToFloat("12").ToString()); 
Console.WriteLine(ConvertToFloat("1 . 10").ToString()); 
Console.WriteLine(ConvertToFloat("100.000,1").ToString()); 

Он возвращает следующие

10,1 
11 
12 
110 
100000,1 

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

Это будет взгляд как этот

float ConvertToFloat(string value) 
{ 
    float result; 

    var converted = float.TryParse(value, 
            out result); 


    if (converted) return result; 

    converted = float.TryParse(value.Replace(".", ","), 
           out result); 

    if (converted) return result; 

    converted = float.TryParse(value, 
            NumberStyles.Currency, 
            CultureInfo.CurrentCulture, 
            out result); 

    return converted ? result : float.NaN; 
} 

Где следующие

Console.WriteLine(ConvertToFloat("10,10").ToString()); 
Console.WriteLine(ConvertToFloat("11,0").ToString()); 
Console.WriteLine(ConvertToFloat("12").ToString()); 
Console.WriteLine(ConvertToFloat("1 . 10").ToString()); 
Console.WriteLine(ConvertToFloat("100.000,1").ToString()); 
Console.WriteLine(ConvertToFloat("asdf").ToString()); 

Возвращает

10,1 
11 
12 
110 
100000,1 
NaN 
+0

на компьютерах с европейским форматом «var convert» всегда будет истинным, потому что он игнорирует ». так как он думает, что. является тысячным сепаратором (100.000.000,0) – Halst

+0

Мой компьютер европейский и 100.000.000,0 не работает вообще. Вы также можете установить второй параметр NumberStyles и CultureInfo. –

+0

ОК, может быть, это просто что-то особенное (моя) датская компьютерная культура, но [var convert = float.TryParse (value, out result); ] дает 123456, когда вход был 123.456 и возвращает true – Halst

2

Разбор использует настройки CultureInfo.CurrentCulture, который отражает язык и номер формат, выбранный пользователем через региональные настройки. Если ваши пользователи вводят десятичные знаки, соответствующие языку, который они выбрали для своих компьютеров, у вас не должно возникнуть проблемы с использованием простого старого double.Parse(). Если пользователь устанавливает свой язык на греческий и набирает «8,5», double.Parse («8,5») вернет 8.5. Если он наберет «8.5», будет возвращен сингл 85.

Если пользователь устанавливает свой локаль в одну настройку и затем начинает использовать неправильную десятичную дробь, вы сталкиваетесь с проблемой. Нет чистого способа разделить такие неправильные записи вместо записей, которые действительно хотели ввести символ группировки. Что вы можете сделать, так это предупредить пользователя, когда число слишком короткое, чтобы включить символ группировки и использовать Masked или числовые текстовые поля для предотвращения неправильных записей.

Другой, несколько более строгий вариант - запретить группировать символ для ввода номера в приложении, отменив его в событии KeyDown ваших текстовых полей. Вы можете получить числовые и группирующие символы из свойства CultureInfo.CurrentCulture.NumberFormat.

Попытка заменить десятичные и группирующие символы обречена на провал, поскольку это зависит от знания во время компиляции того, какой пользователь разделит пользователь. Если бы вы это знали, вы могли просто анализировать номер, используя CultureInfo в уме пользователя. К сожалению, User.Brain.CultureInfo еще не является частью платформы .NET: P

Смежные вопросы