Aquí es mi problema (en-US):

Decimal.Parse("1,2,3,4") devuelve 1234, en lugar de lanzar una InvalidFormatException.

La mayoría de las aplicaciones de Windows (Excel, en-US) no colocar los separadores de miles y no consideran que el valor de un número decimal. El mismo problema ocurre en otros idiomas (aunque con diferentes caracteres).

Hay otros decimal análisis de bibliotecas, hay que resolver este problema?

Gracias!

  • Estás tratando de rechazar cualquier separador de miles, o simplemente extraños? ¿
  • Yo debería haber sido más específico (soy nuevo aquí, lo siento!). Yo no permitir extraños separadores de miles en la cadena. «1,234.00» debería ser válido, mientras que «12,34.00» debe ser incorrecta.
InformationsquelleAutor Eduardo Scoz | 2009-05-06

4 Comentarios

  1. 14

    Le está permitiendo a miles de personas, debido a que por defecto NumberStyles valor utilizado por Decimal.Parse (NumberStyles.Number) incluye NumberStyles.AllowThousands.

    Si desea rechazar los separadores de miles, sólo se puede quitar esa bandera, como este:

    Decimal.Parse("1,2,3,4", NumberStyles.Number ^ NumberStyles.AllowThousands)

    (el código anterior generará una InvalidFormatException, que es lo que quieres, ¿verdad?)

    • Yo no creo que eso es lo que él quiere. Creo que quiere que se considere «de 1.200» válido, pero no «1,2,0,0»… podría estar equivocado, sin embargo.
    • Tienes razón, Max. Todavía necesito el separador de miles, cuando se separa de miles únicamente.
    • Yo aún consideran que el analizador de ser errónea. El separador sólo debe aparecer cada tres dígitos y sólo a la izquierda del punto decimal
    • No veo el analizador saltar separadores decimales como un error, ya que los personajes no tienen ningún significado en matemáticas. Pero sería bueno tener una más estricta versión de que el método que la captura de este..
    • Es de tomar en cuenta la globalización. 123,40 es en realidad 123.40 en danés. Tal vez usted debe pasar a regex para intentar coincidir con la cadena.
    • No realmente, el libro de Josué. Cuando en la configuración regional en-US, Decimal.Analizar convierte «123,40» a 12340.00, en lugar de 123.40. El comportamiento es consistente con otros lugares..

  2. 10

    Terminé de escribir el código para verificar la moneda manualmente. Personalmente, en un marco que se enorgullece por tener todos la globalización cosas incorporado, es increíble .NET no tiene nada que manejar esto.

    Mi solución es la siguiente. Funciona para todas las configuraciones regionales en el marco. No es compatible con los números Negativos, como la de Orión se señala más adelante, sin embargo. ¿Ustedes qué piensan?

        public static bool TryParseCurrency(string value, out decimal result)
        {
            result = 0;
            const int maxCount = 100;
            if (String.IsNullOrEmpty(value))
                return false;
    
            const string decimalNumberPattern = @"^\-?[0-9]{{1,{4}}}(\{0}[0-9]{{{2}}})*(\{0}[0-9]{{{3}}})*(\{1}[0-9]+)*$";
    
            NumberFormatInfo format = CultureInfo.CurrentCulture.NumberFormat;
    
            int secondaryGroupSize = format.CurrencyGroupSizes.Length > 1
                    ? format.CurrencyGroupSizes[1]
                    : format.CurrencyGroupSizes[0];
    
            var r = new Regex(String.Format(decimalNumberPattern
                                           , format.CurrencyGroupSeparator==" " ? "s" : format.CurrencyGroupSeparator
                                           , format.CurrencyDecimalSeparator
                                           , secondaryGroupSize
                                           , format.CurrencyGroupSizes[0]
                                           , maxCount), RegexOptions.Compiled | RegexOptions.CultureInvariant);
            return !r.IsMatch(value.Trim()) ? false : Decimal.TryParse(value, NumberStyles.Any, CultureInfo.CurrentCulture, out result);
        }

    Y he aquí una prueba para mostrar el trabajo (nUnit):

        [Test]
        public void TestCurrencyStrictParsingInAllLocales()
        {
            var originalCulture = CultureInfo.CurrentCulture;
            var cultures = CultureInfo.GetCultures(CultureTypes.SpecificCultures);
            const decimal originalNumber = 12345678.98m;
            foreach(var culture in cultures)
            {
                var stringValue = originalNumber.ToCurrencyWithoutSymbolFormat();
                decimal resultNumber = 0;
                Assert.IsTrue(DecimalUtils.TryParseCurrency(stringValue, out resultNumber));
                Assert.AreEqual(originalNumber, resultNumber);
            }
            System.Threading.Thread.CurrentThread.CurrentCulture = originalCulture;
    
        }
    • Hay un par de cuestiones en términos de uso general. Una gran cantidad de culturas no se utiliza – para representar el signo negativo para incluirla en su regex hace cultura no-neutral. También algunos sistemas de numeración utilizar el signo negativo después de que el número en lugar de en frente (por ejemplo, ‘1234-‘ para ‘-1234’ en en-US). A menudo, usted también tiene que permitir espacios antes o después de la ‘-‘ para algunas culturas. También algunas culturas utilizan paréntesis para números negativos que significa emparejado de uso. De cualquier manera, si sólo se está usando esto para en-US, a continuación, usted debe estar bien.
    • También .Red de apoyo a la moneda de análisis. Usted sólo tiene que pasar en las reglas de divisas para el NumberStyles opción (es decir, NumberStyles.La moneda). Sólo tienen también una interpretación más liberal de la agrupación de los separadores.
    • Hola Oron, gracias por el seguimiento. Tienes razón sobre el signo negativo, esto simplemente no funciona. Esto va a ser utilizado por usuarios de todo el mundo, pero la aplicación no es compatible con la entrada de los valores negativos, por lo que funciona para mí.
    • El principal problema que tengo con esta solución es el rendimiento.
    • sí, el rendimiento de el código como está no es muy grande, pero siempre se puede almacenar en caché el regex objetos, que es lo que yo hice en mi solución (años atrás).
  3. 1

    Usted podría ser capaz de hacer esto en un proceso de dos fases. En primer lugar usted puede verificar el separador de miles, utilizando la información en la CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator y CultureInfo.CurrentCulture.NumberFormat.NumberGroupSizes lanzar una excepción si no pasa y, a continuación, pasar el número en el Decimal.Parse();

    • Gracias, Orion, te voy a dar esta idea de un intento.
    • Totalmente Impresionante nombre!
    • Así que es tuyo Orion!
    • Hola Orion, que terminó con los artículos que usted ha mencionado, además de unos cuantos más. Echa un vistazo a la solución en mi respuesta a continuación, ¿qué te parece?
    • ffs – he wayne.
  4. 0

    Es un problema no resuelto por microsoft.
    Así que, no entiendo por qué 1,2,3.00 (cultura inglesa, por ejemplo) es válida!
    Usted necesita para construir un algoritmo para examinar el tamaño del grupo y devolver false/excepción(como un error doble.parse) si la prueba no está aprobado.
    He tenido un problema similar en una aplicación mvc, que se construyen en el validador no acepta miles..así que me he sobrescribir con una costumbre, el uso de doble/decimal/float.analizar, pero la adición de una lógica para validar el tamaño del grupo.

    Si quieres leer mi solución (se utiliza para mis mvc validador, pero se puede utilizar para tener una mejor doble/decimal/float.analizar genérico validador), vaya aquí
    https://stackoverflow.com/a/41916721/3930528

Dejar respuesta

Please enter your comment!
Please enter your name here