From 6d27931a45506d6c8bd2083eb9e1242ecb5ed4b0 Mon Sep 17 00:00:00 2001 From: John Kerl Date: Mon, 6 Jul 2026 15:38:49 -0400 Subject: [PATCH] Document a thousands-separator recipe for the DSL (#382) Go's fmt package doesn't support the printf apostrophe flag (%'d), and Go's RE2 regex engine doesn't support the lookaheads used by the well-known sed/perl grouping recipe. Add a docs section showing a small user-defined DSL function which inserts thousands separators via repeated sub() application, handling negatives and decimal parts, and passing non-numeric values through unchanged. Co-Authored-By: Claude Fable 5 --- docs/src/reference-main-number-formatting.md | 39 +++++++++++++++++++ .../reference-main-number-formatting.md.in | 35 +++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/docs/src/reference-main-number-formatting.md b/docs/src/reference-main-number-formatting.md index 627cb1748..690b87545 100644 --- a/docs/src/reference-main-number-formatting.md +++ b/docs/src/reference-main-number-formatting.md @@ -84,3 +84,42 @@ x=0xffff,y=0xff,z=16711425
 x=0xffff,y=0xff,z=0xfeff01
 
+ +## Thousands separators + +Some tools accept a `printf`-style apostrophe flag, e.g. `%'d`, to insert +locale-dependent thousands separators, formatting `12345` as `12,345`. Since +Miller's number formatting uses Go's [fmt](https://pkg.go.dev/fmt) package, +which doesn't support that flag, formats like `--ofmt "%'d"`, +`fmtnum($x, "%'d")`, and `format-values -i "%'d"` won't work. Likewise, the +well-known `sed`/`perl` recipe for inserting separators relies on regular-expression +lookaheads such as `(?=...)`, which [Go's regular-expression engine](reference-main-regular-expressions.md) +doesn't support. + +You can, however, insert thousands separators with a small user-defined +[DSL function](reference-dsl-user-defined-functions.md) which applies +[`sub`](reference-dsl-builtin-functions.md#sub) until there's nothing left to +do. Digits are grouped from the left, so the decimal part (if any) is +untouched, and non-numeric values pass through unchanged: + +
+echo 'x=12345,y=1234567.8901,z=-987654321,s=hello' | mlr --opprint put '
+  func commify(n) {
+    s = string(n);
+    while (s =~ "^(-?[0-9]+)([0-9]{3})") {
+      s = sub(s, "^(-?[0-9]+)([0-9]{3})", "\1,\2");
+    }
+    return s;
+  }
+  for (k, v in $*) {
+    $[k] = commify(v);
+  }
+'
+
+
+x      y              z            s
+12,345 1,234,567.8901 -987,654,321 hello
+
+ +To use a separator other than comma -- say, a space or a period -- simply +change the `,` in the `"\1,\2"` replacement string. diff --git a/docs/src/reference-main-number-formatting.md.in b/docs/src/reference-main-number-formatting.md.in index f31ee7d31..740ff96cf 100644 --- a/docs/src/reference-main-number-formatting.md.in +++ b/docs/src/reference-main-number-formatting.md.in @@ -50,3 +50,38 @@ GENMD-EOF GENMD-RUN-COMMAND echo 'x=0xffff,y=0xff' | mlr put '$z=hexfmt($x*$y)' GENMD-EOF + +## Thousands separators + +Some tools accept a `printf`-style apostrophe flag, e.g. `%'d`, to insert +locale-dependent thousands separators, formatting `12345` as `12,345`. Since +Miller's number formatting uses Go's [fmt](https://pkg.go.dev/fmt) package, +which doesn't support that flag, formats like `--ofmt "%'d"`, +`fmtnum($x, "%'d")`, and `format-values -i "%'d"` won't work. Likewise, the +well-known `sed`/`perl` recipe for inserting separators relies on regular-expression +lookaheads such as `(?=...)`, which [Go's regular-expression engine](reference-main-regular-expressions.md) +doesn't support. + +You can, however, insert thousands separators with a small user-defined +[DSL function](reference-dsl-user-defined-functions.md) which applies +[`sub`](reference-dsl-builtin-functions.md#sub) until there's nothing left to +do. Digits are grouped from the left, so the decimal part (if any) is +untouched, and non-numeric values pass through unchanged: + +GENMD-RUN-COMMAND +echo 'x=12345,y=1234567.8901,z=-987654321,s=hello' | mlr --opprint put ' + func commify(n) { + s = string(n); + while (s =~ "^(-?[0-9]+)([0-9]{3})") { + s = sub(s, "^(-?[0-9]+)([0-9]{3})", "\1,\2"); + } + return s; + } + for (k, v in $*) { + $[k] = commify(v); + } +' +GENMD-EOF + +To use a separator other than comma -- say, a space or a period -- simply +change the `,` in the `"\1,\2"` replacement string.