Michael Denny's Blog ;]


Tutto quello che non avresti mai voluto sapere sulle Regular Expression...e se sei qui ti tocca!
Archivio Posts
Anno 2017

Anno 2015

Anno 2014

Anno 2013

Anno 2012

Anno 2010

Anno 2008

Anno 2007

[RegEx In Practice] - Unificare il formato di numeri decimali

Oggi un collega mi ha chiesto se con una regular expression era possibile unificare dei numeri decimali serializzati con un formato eterogeneo, per potere essere convertiti con l'InvariantCulture di .net che prevede il punto come separatore dei decimali e la virgola per le migliaia.

La prima cosa che mi è saltata in mente (forse troppo elaborata, boh non so, ma funziona...) era quella semplicemente di togliere tutti i separatori delle migliaia prima del separatore dei decimali, tenendo conto che potrebbero arrivare numeri con la virgola o con il punto come separatore dei decimali.

Questa è la lista dei casi (input):

1.000.000,00
1.000.000
1,000.30
1000.0
1,000,000.30
1,000,000,000.30
1,000,000
1000,0

e il risultato che vogliamo è questo (output fase 1):

1000000,00
1000000
1000.30
1000.0
1000000.30
1000000000.30
1000000
1000,0

in mondo poi da eseguire un altro replace(",", ".") per concludere la "pulizia" e arrivare in fine a questo (output fase 2):

1000000.00
1000000
1000.30
1000.0
1000000.30
1000000000.30
1000000
1000.0

Per riuscire ad ottenere la scrematura della prima fase ho utilizzato le funzionalità di lookaround delle regular:

(?:,(?=(?:\d+,?)+\.))|(?:\.(?=(?:\d+\.?)+,))|(?:(?<=\.\d+)\.)|(?:\.(?=\d+\.))|(?:(?<=,\d+),)|(?:,(?=\d+,))


ogni pipe "|" (or) praticamente serve ad individuare i separatori delle migliaia nei vari formati con le varie regole del caso:

(?:,(?=(?:\d+,?)+\.))


(?:\.(?=(?:\d+\.?)+,))


(?:(?<=\.\d+)\.)


(?:\.(?=\d+\.))


(?:(?<=,\d+),)


(?:,(?=\d+,))


Dopo la prima "scrematura" basta eseguire un semplce replace della virgola con il punto e fare il cast con l'InvariantCulture per avere la certezza di avere un vero decimale qualsiasi (o quasi) formato possa arrivare, che seguono quelle regole:

void Main()
{
	string SubjectString = "1000,1";
	string ResultString = null;
	Regex RegexObj = new Regex(@"(?:,(?=(?:\d+,?)+\.))|(?:\.(?=(?:\d+\.?)+,))|(?:(?<=\.\d+)\.)|(?:\.(?=\d+\.))|(?:(?<=,\d+),)|(?:,(?=\d+,))");
	ResultString = RegexObj.Replace(SubjectString, "").Replace(",", ".");
	decimal result = decimal.Parse(ResultString, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.InvariantCulture);
	Console.WriteLine(result);
}


Piccolo appunto: la regular in questione non sa distinguere il caso in cui abbiamo un numero così:


100.001


oppure


100,001


non può sapere se volevamo dire cento virgola uno oppure centomila e uno, ma nel caso del mio collega non era necessario prendere altre posizioni, nel caso in cui si dovesse applicare in una situazione più generalizzata si potrebbero individuare questi casi particolari (sempre con una regular) ed evitare di prendere in considerazione il numero, magari mandando un email per avvisare del problema.

martedì, 19 mar 2013 Ore. 17.44
Calendario
ottobre 2017
lmmgvsd
2526272829301
2345678
9101112131415
16171819202122
23242526272829
303112345





Statistiche
  • Views Home Page: 45.572
  • Views Posts: 54.548
  • Views Gallerie: 0
  • n° Posts: 31
  • n° Commenti: 16
Copyright © 2002-2007 - Blogs 2.0
dotNetHell.it | Home Page Blogs
ASP.NET 2.0 Windows 2003