56 lines
2.3 KiB
D
56 lines
2.3 KiB
D
import std.stdio, std.regex, std.range;
|
|
|
|
auto commatize(in char[] txt, in uint start=0, in uint step=3,
|
|
in string ins=",") @safe
|
|
in {
|
|
assert(step > 0);
|
|
} body {
|
|
if (start > txt.length || step > txt.length)
|
|
return txt;
|
|
|
|
// First number may begin with digit or decimal point. Exponents ignored.
|
|
enum decFloField = ctRegex!("[0-9]*\\.[0-9]+|[0-9]+");
|
|
|
|
auto matchDec = matchFirst(txt[start .. $], decFloField);
|
|
if (!matchDec)
|
|
return txt;
|
|
|
|
// Within a decimal float field:
|
|
// A decimal integer field to commatize is positive and not after a point.
|
|
enum decIntField = ctRegex!("(?<=\\.)|[1-9][0-9]*");
|
|
// A decimal fractional field is preceded by a point, and is only digits.
|
|
enum decFracField = ctRegex!("(?<=\\.)[0-9]+");
|
|
|
|
return txt[0 .. start] ~ matchDec.pre ~ matchDec.hit
|
|
.replace!(m => m.hit.retro.chunks(step).join(ins).retro)(decIntField)
|
|
.replace!(m => m.hit.chunks(step).join(ins))(decFracField)
|
|
~ matchDec.post;
|
|
}
|
|
|
|
unittest {
|
|
// An attempted solution may have one or more of the following errors:
|
|
// ignoring a number that has only zero before its decimal point
|
|
assert("0.0123456".commatize == "0.012,345,6");
|
|
// commatizing numbers other than the first
|
|
assert("1000 2.3000".commatize == "1,000 2.3000");
|
|
// only commatizing in one direction from the decimal point
|
|
assert("0001123.456789".commatize == "0001,123.456,789");
|
|
// detecting prefixes such as "Z$" requires detecting other prefixes
|
|
assert(" NZ$300000".commatize == " NZ$300,000");
|
|
// detecting a decimal field that isn't attached to the first number
|
|
assert(" 2600 and .0125".commatize == " 2,600 and .0125");
|
|
// ignoring the start value, or confusing base 0 (used here) with base 1
|
|
assert("1 77000".commatize(1) == "1 77,000");
|
|
// ignoring a number that begins with a point, or treating it as integer
|
|
assert(" .0104004".commatize == " .010,400,4");
|
|
}
|
|
|
|
void main() {
|
|
"pi=3.14159265358979323846264338327950288419716939937510582097494459231"
|
|
.commatize(0, 5, " ").writeln;
|
|
"The author has two Z$100000000000000 Zimbabwe notes (100 trillion)."
|
|
.commatize(0, 3, ".").writeln;
|
|
foreach (const line; "commatizing_numbers_using_defaults.txt".File.byLine)
|
|
line.commatize.writeln;
|
|
}
|