[m-rev.] for review: format ints with thousand separators

Ian MacLarty maclarty at cs.mu.OZ.AU
Thu Feb 3 16:52:52 AEDT 2005


For review by anyone.

Estimated hours taken: 2
Branches: main

Add predicates and functions to the string module to format integers with
thousand separators.

library/string.m
	Add predicate and function to convert an int to a string with 
	commas as thousand separators.  Add a predicate and function to 
	convert an int to any base with any string between any number of 
	digits.

tests/general/string_test.exp
tests/general/string_test.m
	Test the new functionality.

Index: library/string.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/string.m,v
retrieving revision 1.226
diff -u -r1.226 string.m
--- library/string.m	2 Feb 2005 04:28:49 -0000	1.226
+++ library/string.m	3 Feb 2005 05:50:13 -0000
@@ -119,6 +119,13 @@
 :- pred string__int_to_string(int, string).
 :- mode string__int_to_string(in, uo) is det.
 
+	% Convert an integer to a string with commas as thousand seperators.
+	%
+:- func string__int_to_string_thousands(int) = string.
+:- mode string__int_to_string_thousands(in) = uo is det.
+:- pred string__int_to_string_thousands(int, string).
+:- mode string__int_to_string_thousands(in, uo) is det.
+
 	% string__int_to_base_string(Int, Base, String):
 	% Convert an integer to a string in a given Base (between 2 and 36).
 	%
@@ -127,6 +134,17 @@
 :- pred string__int_to_base_string(int, int, string).
 :- mode string__int_to_base_string(in, in, uo) is det.
 
+	% string__int_to_base_string_group(Int, Base, GroupLength, Seperator,
+	%	String):
+	% Convert an integer to a string in a given Base (between 2 and 36)
+	% and insert Seperator between every GroupLength digits.  Useful
+	% for formatting numbers like "1,300,000".
+	%
+:- func string__int_to_base_string_group(int, int, int, string) = string.
+:- mode string__int_to_base_string_group(in, in, in, in) = uo is det.
+:- pred string__int_to_base_string_group(int, int, int, string, string).
+:- mode string__int_to_base_string_group(in, in, in, in, uo) is det.
+
 	% Convert a float to a string.
 	% In the current implementation the resulting float will be in the
 	% form that it was printed using the format string "%#.<prec>g".
@@ -941,6 +959,73 @@
 
 string__from_char_list(CharList, Str) :-
 	string__to_char_list(Str, CharList).
+
+string__int_to_string_thousands(N) = Str :-
+	string__int_to_base_string_group(N, 10, 3, ",", Str).
+
+string__int_to_string_thousands(N, Str) :-
+	string__int_to_base_string_group(N, 10, 3, ",", Str).
+
+string__int_to_base_string_group(N, Base, Period, Sep) = Str :-
+	string__int_to_base_string_group(N, Base, Period, Sep, Str).
+
+string__int_to_base_string_group(N, Base, Period, Sep, Str) :-
+	(
+		Base >= 2, Base =< 36
+	->
+		true
+	;
+		error("string__int_to_base_string_group: invalid base")
+	),
+	string__int_to_base_string_group_1(N, Base, Period, Sep, Str).
+
+:- pred string__int_to_base_string_group_1(int::in, int::in, int::in, 
+	string::in, string::uo) is det.
+
+string__int_to_base_string_group_1(N, Base, Period, Sep, Str) :-
+	% Note that in order to handle MININT correctly,
+	% we need to do the conversion of the absolute
+	% number into digits using negative numbers
+	% (we can't use positive numbers, since -MININT overflows)
+	(
+		N < 0
+	->
+		string__int_to_base_string_group_2(N, Base, 0, Period, Sep, 
+			Str1),
+		string__append("-", Str1, Str)
+	;
+		N1 = 0 - N,
+		string__int_to_base_string_group_2(N1, Base, 0, Period, Sep, 
+			Str)
+	).
+
+:- pred string__int_to_base_string_group_2(int::in, int::in, int::in, int::in,
+	string::in, string::uo) is det.
+
+string__int_to_base_string_group_2(NegN, Base, Curr, Period, Sep, Str) :-
+	(
+		Curr = Period, Period > 0
+	->
+		string__int_to_base_string_group_2(NegN, Base, 0, Period, Sep,
+			Str1),
+		string__append(Str1, Sep, Str)
+	;
+		(
+			NegN > -Base
+		->
+			N = -NegN,
+			char__det_int_to_digit(N, DigitChar),
+			string__char_to_string(DigitChar, Str)
+		;
+			NegN1 = NegN // Base,
+			N10 = (NegN1 * Base) - NegN,
+			char__det_int_to_digit(N10, DigitChar),
+			string__char_to_string(DigitChar, DigitString),
+			string__int_to_base_string_group_2(NegN1, Base, 
+				Curr + 1, Period, Sep, Str1),
+			string__append(Str1, DigitString, Str)
+		)
+	).
 
 /*-----------------------------------------------------------------------*/
 
Index: tests/general/string_test.exp
===================================================================
RCS file: /home/mercury1/repository/tests/general/string_test.exp,v
retrieving revision 1.1
diff -u -r1.1 string_test.exp
--- tests/general/string_test.exp	4 Nov 1996 07:08:47 -0000	1.1
+++ tests/general/string_test.exp	3 Feb 2005 05:32:52 -0000
@@ -6,6 +6,10 @@
 int_to_string 1234: 1234
 octal 1234: 2322
 hexadecimal 1234: 4D2
+Grouped 1234: 1,234
+Grouped 113: 1--1--1--0--0--0--1
+Grouped 1300000: 1,300,000
+Non Grouped 45999: 45999
 string_to_int 5678: 5678
 Five f's: fffff
 Five f's and five dots: fffff.....
Index: tests/general/string_test.m
===================================================================
RCS file: /home/mercury1/repository/tests/general/string_test.m,v
retrieving revision 1.3
diff -u -r1.3 string_test.m
--- tests/general/string_test.m	1 Dec 2003 15:56:07 -0000	1.3
+++ tests/general/string_test.m	3 Feb 2005 05:30:40 -0000
@@ -31,6 +31,14 @@
 	write_message("octal 1234: ", Num8),
 	{ string__int_to_base_string(1234, 16, Num16) },
 	write_message("hexadecimal 1234: ", Num16),
+	{ string__int_to_base_string_group(1234, 10, 3, ",", NumG1) },
+	write_message("Grouped 1234: ", NumG1),
+	{ string__int_to_base_string_group(113, 2, 1, "--", NumG2) },
+	write_message("Grouped 113: ", NumG2),
+	{ string__int_to_base_string_group(1300000, 10, 3, ",", NumG3) },
+	write_message("Grouped 1300000: ", NumG3),
+	{ string__int_to_base_string_group(45999, 10, 0, ",", NumG4) },
+	write_message("Non Grouped 45999: ", NumG4),
 	{ string__duplicate_char('f', 5, FiveFs) },
 	( { string__to_int("5678", Num5678) } ->
 		io__write_string("string_to_int 5678: "),
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list