From ee0ac3d7bb6ea25ae8d514890de65b8a533e0247 Mon Sep 17 00:00:00 2001 From: John Kerl Date: Sun, 26 Feb 2023 17:14:35 -0500 Subject: [PATCH] New `leftpad` and `rightpad` DSL functions (#1205) * Initial code for `leftpad` and `rightpad` functions * typofix, and test cases * doc-gen * windows UT --- docs/src/manpage.md | 38 +++++++---- docs/src/manpage.txt | 38 +++++++---- docs/src/reference-dsl-builtin-functions.md | 22 +++++- docs/src/reference-verbs.md | 3 +- internal/pkg/bifs/strings.go | 67 +++++++++++++++++++ .../pkg/dsl/cst/builtin_function_manager.go | 23 +++++++ man/manpage.txt | 38 +++++++---- man/mlr.1 | 52 ++++++++++---- test/cases/dsl-leftpad-rightpad/L001/cmd | 1 + test/cases/dsl-leftpad-rightpad/L001/experr | 0 test/cases/dsl-leftpad-rightpad/L001/expout | 11 +++ test/cases/dsl-leftpad-rightpad/L001/mlr | 1 + test/cases/dsl-leftpad-rightpad/L002/cmd | 1 + test/cases/dsl-leftpad-rightpad/L002/experr | 0 test/cases/dsl-leftpad-rightpad/L002/expout | 11 +++ test/cases/dsl-leftpad-rightpad/L002/mlr | 1 + test/cases/dsl-leftpad-rightpad/L003/cmd | 1 + test/cases/dsl-leftpad-rightpad/L003/experr | 0 test/cases/dsl-leftpad-rightpad/L003/expout | 11 +++ test/cases/dsl-leftpad-rightpad/L003/mlr | 1 + test/cases/dsl-leftpad-rightpad/L004/cmd | 1 + test/cases/dsl-leftpad-rightpad/L004/experr | 0 test/cases/dsl-leftpad-rightpad/L004/expout | 11 +++ test/cases/dsl-leftpad-rightpad/L004/mlr | 1 + test/cases/dsl-leftpad-rightpad/L005/cmd | 1 + test/cases/dsl-leftpad-rightpad/L005/experr | 0 test/cases/dsl-leftpad-rightpad/L005/expout | 11 +++ test/cases/dsl-leftpad-rightpad/L005/mlr | 1 + test/cases/dsl-leftpad-rightpad/R001/cmd | 1 + test/cases/dsl-leftpad-rightpad/R001/experr | 0 test/cases/dsl-leftpad-rightpad/R001/expout | 11 +++ test/cases/dsl-leftpad-rightpad/R001/mlr | 1 + test/cases/dsl-leftpad-rightpad/R002/cmd | 1 + test/cases/dsl-leftpad-rightpad/R002/experr | 0 test/cases/dsl-leftpad-rightpad/R002/expout | 11 +++ test/cases/dsl-leftpad-rightpad/R002/mlr | 1 + test/cases/dsl-leftpad-rightpad/R003/cmd | 1 + test/cases/dsl-leftpad-rightpad/R003/experr | 0 test/cases/dsl-leftpad-rightpad/R003/expout | 11 +++ test/cases/dsl-leftpad-rightpad/R003/mlr | 1 + test/cases/dsl-leftpad-rightpad/R004/cmd | 1 + test/cases/dsl-leftpad-rightpad/R004/experr | 0 test/cases/dsl-leftpad-rightpad/R004/expout | 11 +++ test/cases/dsl-leftpad-rightpad/R004/mlr | 1 + test/cases/dsl-leftpad-rightpad/R005/cmd | 1 + test/cases/dsl-leftpad-rightpad/R005/experr | 0 test/cases/dsl-leftpad-rightpad/R005/expout | 11 +++ test/cases/dsl-leftpad-rightpad/R005/mlr | 1 + 48 files changed, 360 insertions(+), 51 deletions(-) create mode 100644 test/cases/dsl-leftpad-rightpad/L001/cmd create mode 100644 test/cases/dsl-leftpad-rightpad/L001/experr create mode 100644 test/cases/dsl-leftpad-rightpad/L001/expout create mode 100644 test/cases/dsl-leftpad-rightpad/L001/mlr create mode 100644 test/cases/dsl-leftpad-rightpad/L002/cmd create mode 100644 test/cases/dsl-leftpad-rightpad/L002/experr create mode 100644 test/cases/dsl-leftpad-rightpad/L002/expout create mode 100644 test/cases/dsl-leftpad-rightpad/L002/mlr create mode 100644 test/cases/dsl-leftpad-rightpad/L003/cmd create mode 100644 test/cases/dsl-leftpad-rightpad/L003/experr create mode 100644 test/cases/dsl-leftpad-rightpad/L003/expout create mode 100644 test/cases/dsl-leftpad-rightpad/L003/mlr create mode 100644 test/cases/dsl-leftpad-rightpad/L004/cmd create mode 100644 test/cases/dsl-leftpad-rightpad/L004/experr create mode 100644 test/cases/dsl-leftpad-rightpad/L004/expout create mode 100644 test/cases/dsl-leftpad-rightpad/L004/mlr create mode 100644 test/cases/dsl-leftpad-rightpad/L005/cmd create mode 100644 test/cases/dsl-leftpad-rightpad/L005/experr create mode 100644 test/cases/dsl-leftpad-rightpad/L005/expout create mode 100644 test/cases/dsl-leftpad-rightpad/L005/mlr create mode 100644 test/cases/dsl-leftpad-rightpad/R001/cmd create mode 100644 test/cases/dsl-leftpad-rightpad/R001/experr create mode 100644 test/cases/dsl-leftpad-rightpad/R001/expout create mode 100644 test/cases/dsl-leftpad-rightpad/R001/mlr create mode 100644 test/cases/dsl-leftpad-rightpad/R002/cmd create mode 100644 test/cases/dsl-leftpad-rightpad/R002/experr create mode 100644 test/cases/dsl-leftpad-rightpad/R002/expout create mode 100644 test/cases/dsl-leftpad-rightpad/R002/mlr create mode 100644 test/cases/dsl-leftpad-rightpad/R003/cmd create mode 100644 test/cases/dsl-leftpad-rightpad/R003/experr create mode 100644 test/cases/dsl-leftpad-rightpad/R003/expout create mode 100644 test/cases/dsl-leftpad-rightpad/R003/mlr create mode 100644 test/cases/dsl-leftpad-rightpad/R004/cmd create mode 100644 test/cases/dsl-leftpad-rightpad/R004/experr create mode 100644 test/cases/dsl-leftpad-rightpad/R004/expout create mode 100644 test/cases/dsl-leftpad-rightpad/R004/mlr create mode 100644 test/cases/dsl-leftpad-rightpad/R005/cmd create mode 100644 test/cases/dsl-leftpad-rightpad/R005/experr create mode 100644 test/cases/dsl-leftpad-rightpad/R005/expout create mode 100644 test/cases/dsl-leftpad-rightpad/R005/mlr diff --git a/docs/src/manpage.md b/docs/src/manpage.md index c812d30b6..73bab7b90 100644 --- a/docs/src/manpage.md +++ b/docs/src/manpage.md @@ -213,17 +213,17 @@ MILLER(1) MILLER(1) invqnorm is_absent is_array is_bool is_boolean is_empty is_empty_map is_error is_float is_int is_map is_nan is_nonempty_map is_not_array is_not_empty is_not_map is_not_null is_null is_numeric is_present is_string joink joinkv - joinv json_parse json_stringify latin1_to_utf8 leafcount length localtime2gmt - localtime2sec log log10 log1p logifit lstrip madd mapdiff mapexcept mapselect - mapsum max md5 mexp min mmul msub os pow qnorm reduce regextract - regextract_or_else round roundm rstrip sec2dhms sec2gmt sec2gmtdate sec2hms - sec2localdate sec2localtime select sgn sha1 sha256 sha512 sin sinh sort splita - splitax splitkv splitkvx splitnv splitnvx sqrt ssub strftime strftime_local - string strip strlen strptime strptime_local sub substr substr0 substr1 system - systime systimeint tan tanh tolower toupper truncate typeof unflatten unformat - unformatx uptime urand urand32 urandelement urandint urandrange utf8_to_latin1 - version ! != !=~ % & && * ** + - . .* .+ .- ./ / // < << <= <=> == =~ > >= >> - >>> ?: ?? ??? ^ ^^ | || ~ + joinv json_parse json_stringify latin1_to_utf8 leafcount leftpad length + localtime2gmt localtime2sec log log10 log1p logifit lstrip madd mapdiff + mapexcept mapselect mapsum max md5 mexp min mmul msub os pow qnorm reduce + regextract regextract_or_else rightpad round roundm rstrip sec2dhms sec2gmt + sec2gmtdate sec2hms sec2localdate sec2localtime select sgn sha1 sha256 sha512 + sin sinh sort splita splitax splitkv splitkvx splitnv splitnvx sqrt ssub + strftime strftime_local string strip strlen strptime strptime_local sub substr + substr0 substr1 system systime systimeint tan tanh tolower toupper truncate + typeof unflatten unformat unformatx uptime urand urand32 urandelement urandint + urandrange utf8_to_latin1 version ! != !=~ % & && * ** + - . .* .+ .- ./ / // + < << <= <=> == =~ > >= >> >>> ?: ?? ??? ^ ^^ | || ~ 1mCOMMENTS-IN-DATA FLAGS0m Miller lets you put comments in your data, such as @@ -2459,6 +2459,13 @@ MILLER(1) MILLER(1) 1mleafcount0m (class=collections #args=1) Counts total number of terminal values in map/array. For single-level map/array, same as length. + 1mleftpad0m + (class=string #args=3) Left-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first. + Examples: + leftpad("abcdefg", 10 , "*") gives "***abcdefg". + leftpad("abcdefg", 10 , "XY") gives "XYabcdefg". + leftpad("1234567", 10 , "0") gives "0001234567". + 1mlength0m (class=collections #args=1) Counts number of top-level entries in array/map. Scalars have length 1. @@ -2549,6 +2556,13 @@ MILLER(1) MILLER(1) regextract_or_else("index ab09 file", "[a-z][a-z][0-9][0-9]", "nonesuch") gives "ab09" regextract_or_else("index a999 file", "[a-z][a-z][0-9][0-9]", "nonesuch") gives "nonesuch" + 1mrightpad0m + (class=string #args=3) Right-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first. + Examples: + rightpad("abcdefg", 10 , "*") gives "abcdefg***". + rightpad("abcdefg", 10 , "XY") gives "abcdefgXY". + rightpad("1234567", 10 , "0") gives "1234567000". + 1mround0m (class=math #args=1) Round to nearest integer. @@ -3297,5 +3311,5 @@ MILLER(1) MILLER(1) - 2023-01-28 MILLER(1) + 2023-02-26 MILLER(1) diff --git a/docs/src/manpage.txt b/docs/src/manpage.txt index 57735a703..82f967235 100644 --- a/docs/src/manpage.txt +++ b/docs/src/manpage.txt @@ -192,17 +192,17 @@ MILLER(1) MILLER(1) invqnorm is_absent is_array is_bool is_boolean is_empty is_empty_map is_error is_float is_int is_map is_nan is_nonempty_map is_not_array is_not_empty is_not_map is_not_null is_null is_numeric is_present is_string joink joinkv - joinv json_parse json_stringify latin1_to_utf8 leafcount length localtime2gmt - localtime2sec log log10 log1p logifit lstrip madd mapdiff mapexcept mapselect - mapsum max md5 mexp min mmul msub os pow qnorm reduce regextract - regextract_or_else round roundm rstrip sec2dhms sec2gmt sec2gmtdate sec2hms - sec2localdate sec2localtime select sgn sha1 sha256 sha512 sin sinh sort splita - splitax splitkv splitkvx splitnv splitnvx sqrt ssub strftime strftime_local - string strip strlen strptime strptime_local sub substr substr0 substr1 system - systime systimeint tan tanh tolower toupper truncate typeof unflatten unformat - unformatx uptime urand urand32 urandelement urandint urandrange utf8_to_latin1 - version ! != !=~ % & && * ** + - . .* .+ .- ./ / // < << <= <=> == =~ > >= >> - >>> ?: ?? ??? ^ ^^ | || ~ + joinv json_parse json_stringify latin1_to_utf8 leafcount leftpad length + localtime2gmt localtime2sec log log10 log1p logifit lstrip madd mapdiff + mapexcept mapselect mapsum max md5 mexp min mmul msub os pow qnorm reduce + regextract regextract_or_else rightpad round roundm rstrip sec2dhms sec2gmt + sec2gmtdate sec2hms sec2localdate sec2localtime select sgn sha1 sha256 sha512 + sin sinh sort splita splitax splitkv splitkvx splitnv splitnvx sqrt ssub + strftime strftime_local string strip strlen strptime strptime_local sub substr + substr0 substr1 system systime systimeint tan tanh tolower toupper truncate + typeof unflatten unformat unformatx uptime urand urand32 urandelement urandint + urandrange utf8_to_latin1 version ! != !=~ % & && * ** + - . .* .+ .- ./ / // + < << <= <=> == =~ > >= >> >>> ?: ?? ??? ^ ^^ | || ~ 1mCOMMENTS-IN-DATA FLAGS0m Miller lets you put comments in your data, such as @@ -2438,6 +2438,13 @@ MILLER(1) MILLER(1) 1mleafcount0m (class=collections #args=1) Counts total number of terminal values in map/array. For single-level map/array, same as length. + 1mleftpad0m + (class=string #args=3) Left-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first. + Examples: + leftpad("abcdefg", 10 , "*") gives "***abcdefg". + leftpad("abcdefg", 10 , "XY") gives "XYabcdefg". + leftpad("1234567", 10 , "0") gives "0001234567". + 1mlength0m (class=collections #args=1) Counts number of top-level entries in array/map. Scalars have length 1. @@ -2528,6 +2535,13 @@ MILLER(1) MILLER(1) regextract_or_else("index ab09 file", "[a-z][a-z][0-9][0-9]", "nonesuch") gives "ab09" regextract_or_else("index a999 file", "[a-z][a-z][0-9][0-9]", "nonesuch") gives "nonesuch" + 1mrightpad0m + (class=string #args=3) Right-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first. + Examples: + rightpad("abcdefg", 10 , "*") gives "abcdefg***". + rightpad("abcdefg", 10 , "XY") gives "abcdefgXY". + rightpad("1234567", 10 , "0") gives "1234567000". + 1mround0m (class=math #args=1) Round to nearest integer. @@ -3276,4 +3290,4 @@ MILLER(1) MILLER(1) - 2023-01-28 MILLER(1) + 2023-02-26 MILLER(1) diff --git a/docs/src/reference-dsl-builtin-functions.md b/docs/src/reference-dsl-builtin-functions.md index bbb65a5eb..116c00be7 100644 --- a/docs/src/reference-dsl-builtin-functions.md +++ b/docs/src/reference-dsl-builtin-functions.md @@ -74,7 +74,7 @@ is 2. Unary operators such as `!` and `~` show argument-count of 1; the ternary * [**Hashing functions**](#hashing-functions): [md5](#md5), [sha1](#sha1), [sha256](#sha256), [sha512](#sha512). * [**Higher-order-functions functions**](#higher-order-functions-functions): [any](#any), [apply](#apply), [every](#every), [fold](#fold), [reduce](#reduce), [select](#select), [sort](#sort). * [**Math functions**](#math-functions): [abs](#abs), [acos](#acos), [acosh](#acosh), [asin](#asin), [asinh](#asinh), [atan](#atan), [atan2](#atan2), [atanh](#atanh), [cbrt](#cbrt), [ceil](#ceil), [cos](#cos), [cosh](#cosh), [erf](#erf), [erfc](#erfc), [exp](#exp), [expm1](#expm1), [floor](#floor), [invqnorm](#invqnorm), [log](#log), [log10](#log10), [log1p](#log1p), [logifit](#logifit), [max](#max), [min](#min), [qnorm](#qnorm), [round](#round), [roundm](#roundm), [sgn](#sgn), [sin](#sin), [sinh](#sinh), [sqrt](#sqrt), [tan](#tan), [tanh](#tanh), [urand](#urand), [urand32](#urand32), [urandelement](#urandelement), [urandint](#urandint), [urandrange](#urandrange). -* [**String functions**](#string-functions): [capitalize](#capitalize), [clean_whitespace](#clean_whitespace), [collapse_whitespace](#collapse_whitespace), [format](#format), [gssub](#gssub), [gsub](#gsub), [latin1_to_utf8](#latin1_to_utf8), [lstrip](#lstrip), [regextract](#regextract), [regextract_or_else](#regextract_or_else), [rstrip](#rstrip), [ssub](#ssub), [strip](#strip), [strlen](#strlen), [sub](#sub), [substr](#substr), [substr0](#substr0), [substr1](#substr1), [tolower](#tolower), [toupper](#toupper), [truncate](#truncate), [unformat](#unformat), [unformatx](#unformatx), [utf8_to_latin1](#utf8_to_latin1), [\.](#dot). +* [**String functions**](#string-functions): [capitalize](#capitalize), [clean_whitespace](#clean_whitespace), [collapse_whitespace](#collapse_whitespace), [format](#format), [gssub](#gssub), [gsub](#gsub), [latin1_to_utf8](#latin1_to_utf8), [leftpad](#leftpad), [lstrip](#lstrip), [regextract](#regextract), [regextract_or_else](#regextract_or_else), [rightpad](#rightpad), [rstrip](#rstrip), [ssub](#ssub), [strip](#strip), [strlen](#strlen), [sub](#sub), [substr](#substr), [substr0](#substr0), [substr1](#substr1), [tolower](#tolower), [toupper](#toupper), [truncate](#truncate), [unformat](#unformat), [unformatx](#unformatx), [utf8_to_latin1](#utf8_to_latin1), [\.](#dot). * [**System functions**](#system-functions): [exec](#exec), [hostname](#hostname), [os](#os), [system](#system), [version](#version). * [**Time functions**](#time-functions): [dhms2fsec](#dhms2fsec), [dhms2sec](#dhms2sec), [fsec2dhms](#fsec2dhms), [fsec2hms](#fsec2hms), [gmt2localtime](#gmt2localtime), [gmt2sec](#gmt2sec), [hms2fsec](#hms2fsec), [hms2sec](#hms2sec), [localtime2gmt](#localtime2gmt), [localtime2sec](#localtime2sec), [sec2dhms](#sec2dhms), [sec2gmt](#sec2gmt), [sec2gmtdate](#sec2gmtdate), [sec2hms](#sec2hms), [sec2localdate](#sec2localdate), [sec2localtime](#sec2localtime), [strftime](#strftime), [strftime_local](#strftime_local), [strptime](#strptime), [strptime_local](#strptime_local), [systime](#systime), [systimeint](#systimeint), [uptime](#uptime). * [**Typing functions**](#typing-functions): [asserting_absent](#asserting_absent), [asserting_array](#asserting_array), [asserting_bool](#asserting_bool), [asserting_boolean](#asserting_boolean), [asserting_empty](#asserting_empty), [asserting_empty_map](#asserting_empty_map), [asserting_error](#asserting_error), [asserting_float](#asserting_float), [asserting_int](#asserting_int), [asserting_map](#asserting_map), [asserting_nonempty_map](#asserting_nonempty_map), [asserting_not_array](#asserting_not_array), [asserting_not_empty](#asserting_not_empty), [asserting_not_map](#asserting_not_map), [asserting_not_null](#asserting_not_null), [asserting_null](#asserting_null), [asserting_numeric](#asserting_numeric), [asserting_present](#asserting_present), [asserting_string](#asserting_string), [is_absent](#is_absent), [is_array](#is_array), [is_bool](#is_bool), [is_boolean](#is_boolean), [is_empty](#is_empty), [is_empty_map](#is_empty_map), [is_error](#is_error), [is_float](#is_float), [is_int](#is_int), [is_map](#is_map), [is_nan](#is_nan), [is_nonempty_map](#is_nonempty_map), [is_not_array](#is_not_array), [is_not_empty](#is_not_empty), [is_not_map](#is_not_map), [is_not_null](#is_not_null), [is_null](#is_null), [is_numeric](#is_numeric), [is_present](#is_present), [is_string](#is_string), [typeof](#typeof). @@ -1024,6 +1024,16 @@ $* = latin1_to_utf8($*) +### leftpad +
+leftpad  (class=string #args=3) Left-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first.
+Examples:
+leftpad("abcdefg", 10 , "*") gives "***abcdefg".
+leftpad("abcdefg", 10 , "XY") gives "XYabcdefg".
+leftpad("1234567", 10 , "0") gives "0001234567".
+
+ + ### lstrip
 lstrip  (class=string #args=1) Strip leading whitespace from string.
@@ -1048,6 +1058,16 @@ regextract_or_else("index a999 file", "[a-z][a-z][0-9][0-9]", "nonesuch") gives
 
+### rightpad +
+rightpad  (class=string #args=3) Right-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first.
+Examples:
+rightpad("abcdefg", 10 , "*") gives "abcdefg***".
+rightpad("abcdefg", 10 , "XY") gives "abcdefgXY".
+rightpad("1234567", 10 , "0") gives "1234567000".
+
+ + ### rstrip
 rstrip  (class=string #args=1) Strip trailing whitespace from string.
diff --git a/docs/src/reference-verbs.md b/docs/src/reference-verbs.md
index 94d74a749..6bc3fd8bf 100644
--- a/docs/src/reference-verbs.md
+++ b/docs/src/reference-verbs.md
@@ -2264,7 +2264,8 @@ More example put expressions:
     '$new_field = $index**2; $qn = $quantity * $new_field'
   Regex-replacement:
     '$name = sub($name, "http.*com"i, "")'
-    'if ($a =~ "([a-z]+)_([0-9]+)") { $b = "left_\1"; $c = "right_\2" }'
+  Regex-capture:
+	'if ($a =~ "([a-z]+)_([0-9]+)") { $b = "left_\1"; $c = "right_\2" }'
   Built-in variables:
     '$filename = FILENAME'
   Aggregations (use mlr put -q):
diff --git a/internal/pkg/bifs/strings.go b/internal/pkg/bifs/strings.go
index 7f51ad9bd..46c86e28d 100644
--- a/internal/pkg/bifs/strings.go
+++ b/internal/pkg/bifs/strings.go
@@ -154,6 +154,73 @@ func BIF_truncate(input1, input2 *mlrval.Mlrval) *mlrval.Mlrval {
 	}
 }
 
+// ================================================================
+func BIF_leftpad(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
+	if input1.IsErrorOrAbsent() {
+		return input1
+	}
+	if input2.IsErrorOrAbsent() {
+		return input2
+	}
+	if input3.IsErrorOrAbsent() {
+		return input3
+	}
+
+	if !input2.IsInt() {
+		return mlrval.ERROR
+	}
+
+	inputString := input1.String()
+	padString := input3.String()
+
+	inputLength := lib.UTF8Strlen(inputString)
+	padLength := lib.UTF8Strlen(padString)
+	targetLength := input2.AcquireIntValue()
+	outputLength := inputLength
+
+	var buffer bytes.Buffer
+	for outputLength+padLength <= targetLength {
+		buffer.WriteString(padString)
+		outputLength += padLength
+	}
+	buffer.WriteString(inputString)
+
+	return mlrval.FromString(buffer.String())
+}
+
+func BIF_rightpad(input1, input2, input3 *mlrval.Mlrval) *mlrval.Mlrval {
+	if input1.IsErrorOrAbsent() {
+		return input1
+	}
+	if input2.IsErrorOrAbsent() {
+		return input2
+	}
+	if input3.IsErrorOrAbsent() {
+		return input3
+	}
+
+	if !input2.IsInt() {
+		return mlrval.ERROR
+	}
+
+	inputString := input1.String()
+	padString := input3.String()
+
+	inputLength := lib.UTF8Strlen(inputString)
+	padLength := lib.UTF8Strlen(padString)
+	targetLength := input2.AcquireIntValue()
+	outputLength := inputLength
+
+	var buffer bytes.Buffer
+	buffer.WriteString(inputString)
+	for outputLength+padLength <= targetLength {
+		buffer.WriteString(padString)
+		outputLength += padLength
+	}
+
+	return mlrval.FromString(buffer.String())
+}
+
 // ================================================================
 func BIF_lstrip(input1 *mlrval.Mlrval) *mlrval.Mlrval {
 	if input1.IsString() {
diff --git a/internal/pkg/dsl/cst/builtin_function_manager.go b/internal/pkg/dsl/cst/builtin_function_manager.go
index 929cc5b4d..72ae7558b 100644
--- a/internal/pkg/dsl/cst/builtin_function_manager.go
+++ b/internal/pkg/dsl/cst/builtin_function_manager.go
@@ -560,6 +560,29 @@ Arrays are new in Miller 6; the substr function is older.`,
 			binaryFunc: bifs.BIF_truncate,
 		},
 
+		{
+			name:        "leftpad",
+			class:       FUNC_CLASS_STRING,
+			help:        `Left-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first.`,
+			ternaryFunc: bifs.BIF_leftpad,
+			examples: []string{
+				`leftpad("abcdefg", 10 , "*") gives "***abcdefg".`,
+				`leftpad("abcdefg", 10 , "XY") gives "XYabcdefg".`,
+				`leftpad("1234567", 10 , "0") gives "0001234567".`,
+			},
+		},
+		{
+			name:        "rightpad",
+			class:       FUNC_CLASS_STRING,
+			help:        `Right-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first.`,
+			ternaryFunc: bifs.BIF_rightpad,
+			examples: []string{
+				`rightpad("abcdefg", 10 , "*") gives "abcdefg***".`,
+				`rightpad("abcdefg", 10 , "XY") gives "abcdefgXY".`,
+				`rightpad("1234567", 10 , "0") gives "1234567000".`,
+			},
+		},
+
 		{
 			name:  "format",
 			class: FUNC_CLASS_STRING,
diff --git a/man/manpage.txt b/man/manpage.txt
index 57735a703..82f967235 100644
--- a/man/manpage.txt
+++ b/man/manpage.txt
@@ -192,17 +192,17 @@ MILLER(1)                                                            MILLER(1)
        invqnorm is_absent is_array is_bool is_boolean is_empty is_empty_map is_error
        is_float is_int is_map is_nan is_nonempty_map is_not_array is_not_empty
        is_not_map is_not_null is_null is_numeric is_present is_string joink joinkv
-       joinv json_parse json_stringify latin1_to_utf8 leafcount length localtime2gmt
-       localtime2sec log log10 log1p logifit lstrip madd mapdiff mapexcept mapselect
-       mapsum max md5 mexp min mmul msub os pow qnorm reduce regextract
-       regextract_or_else round roundm rstrip sec2dhms sec2gmt sec2gmtdate sec2hms
-       sec2localdate sec2localtime select sgn sha1 sha256 sha512 sin sinh sort splita
-       splitax splitkv splitkvx splitnv splitnvx sqrt ssub strftime strftime_local
-       string strip strlen strptime strptime_local sub substr substr0 substr1 system
-       systime systimeint tan tanh tolower toupper truncate typeof unflatten unformat
-       unformatx uptime urand urand32 urandelement urandint urandrange utf8_to_latin1
-       version ! != !=~ % & && * ** + - . .* .+ .- ./ / // < << <= <=> == =~ > >= >>
-       >>> ?: ?? ??? ^ ^^ | || ~
+       joinv json_parse json_stringify latin1_to_utf8 leafcount leftpad length
+       localtime2gmt localtime2sec log log10 log1p logifit lstrip madd mapdiff
+       mapexcept mapselect mapsum max md5 mexp min mmul msub os pow qnorm reduce
+       regextract regextract_or_else rightpad round roundm rstrip sec2dhms sec2gmt
+       sec2gmtdate sec2hms sec2localdate sec2localtime select sgn sha1 sha256 sha512
+       sin sinh sort splita splitax splitkv splitkvx splitnv splitnvx sqrt ssub
+       strftime strftime_local string strip strlen strptime strptime_local sub substr
+       substr0 substr1 system systime systimeint tan tanh tolower toupper truncate
+       typeof unflatten unformat unformatx uptime urand urand32 urandelement urandint
+       urandrange utf8_to_latin1 version ! != !=~ % & && * ** + - . .* .+ .- ./ / //
+       < << <= <=> == =~ > >= >> >>> ?: ?? ??? ^ ^^ | || ~
 
 1mCOMMENTS-IN-DATA FLAGS0m
        Miller lets you put comments in your data, such as
@@ -2438,6 +2438,13 @@ MILLER(1)                                                            MILLER(1)
    1mleafcount0m
         (class=collections #args=1) Counts total number of terminal values in map/array. For single-level map/array, same as length.
 
+   1mleftpad0m
+        (class=string #args=3) Left-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first.
+       Examples:
+       leftpad("abcdefg", 10 , "*") gives "***abcdefg".
+       leftpad("abcdefg", 10 , "XY") gives "XYabcdefg".
+       leftpad("1234567", 10 , "0") gives "0001234567".
+
    1mlength0m
         (class=collections #args=1) Counts number of top-level entries in array/map. Scalars have length 1.
 
@@ -2528,6 +2535,13 @@ MILLER(1)                                                            MILLER(1)
        regextract_or_else("index ab09 file", "[a-z][a-z][0-9][0-9]", "nonesuch") gives "ab09"
        regextract_or_else("index a999 file", "[a-z][a-z][0-9][0-9]", "nonesuch") gives "nonesuch"
 
+   1mrightpad0m
+        (class=string #args=3) Right-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first.
+       Examples:
+       rightpad("abcdefg", 10 , "*") gives "abcdefg***".
+       rightpad("abcdefg", 10 , "XY") gives "abcdefgXY".
+       rightpad("1234567", 10 , "0") gives "1234567000".
+
    1mround0m
         (class=math #args=1) Round to nearest integer.
 
@@ -3276,4 +3290,4 @@ MILLER(1)                                                            MILLER(1)
 
 
 
-                                  2023-01-28                         MILLER(1)
+                                  2023-02-26                         MILLER(1)
diff --git a/man/mlr.1 b/man/mlr.1
index 238d71940..8344e77c0 100644
--- a/man/mlr.1
+++ b/man/mlr.1
@@ -2,12 +2,12 @@
 .\"     Title: mlr
 .\"    Author: [see the "AUTHOR" section]
 .\" Generator: ./mkman.rb
-.\"      Date: 2023-01-28
+.\"      Date: 2023-02-26
 .\"    Manual: \ \&
 .\"    Source: \ \&
 .\"  Language: English
 .\"
-.TH "MILLER" "1" "2023-01-28" "\ \&" "\ \&"
+.TH "MILLER" "1" "2023-02-26" "\ \&" "\ \&"
 .\" -----------------------------------------------------------------
 .\" * Portability definitions
 .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -239,17 +239,17 @@ gmt2localtime gmt2sec gssub gsub haskey hexfmt hms2fsec hms2sec hostname int
 invqnorm is_absent is_array is_bool is_boolean is_empty is_empty_map is_error
 is_float is_int is_map is_nan is_nonempty_map is_not_array is_not_empty
 is_not_map is_not_null is_null is_numeric is_present is_string joink joinkv
-joinv json_parse json_stringify latin1_to_utf8 leafcount length localtime2gmt
-localtime2sec log log10 log1p logifit lstrip madd mapdiff mapexcept mapselect
-mapsum max md5 mexp min mmul msub os pow qnorm reduce regextract
-regextract_or_else round roundm rstrip sec2dhms sec2gmt sec2gmtdate sec2hms
-sec2localdate sec2localtime select sgn sha1 sha256 sha512 sin sinh sort splita
-splitax splitkv splitkvx splitnv splitnvx sqrt ssub strftime strftime_local
-string strip strlen strptime strptime_local sub substr substr0 substr1 system
-systime systimeint tan tanh tolower toupper truncate typeof unflatten unformat
-unformatx uptime urand urand32 urandelement urandint urandrange utf8_to_latin1
-version ! != !=~ % & && * ** + - . .* .+ .- ./ / // < << <= <=> == =~ > >= >>
->>> ?: ?? ??? ^ ^^ | || ~
+joinv json_parse json_stringify latin1_to_utf8 leafcount leftpad length
+localtime2gmt localtime2sec log log10 log1p logifit lstrip madd mapdiff
+mapexcept mapselect mapsum max md5 mexp min mmul msub os pow qnorm reduce
+regextract regextract_or_else rightpad round roundm rstrip sec2dhms sec2gmt
+sec2gmtdate sec2hms sec2localdate sec2localtime select sgn sha1 sha256 sha512
+sin sinh sort splita splitax splitkv splitkvx splitnv splitnvx sqrt ssub
+strftime strftime_local string strip strlen strptime strptime_local sub substr
+substr0 substr1 system systime systimeint tan tanh tolower toupper truncate
+typeof unflatten unformat unformatx uptime urand urand32 urandelement urandint
+urandrange utf8_to_latin1 version ! != !=~ % & && * ** + - . .* .+ .- ./ / //
+< << <= <=> == =~ > >= >> >>> ?: ?? ??? ^ ^^ | || ~
 .fi
 .if n \{\
 .RE
@@ -3591,6 +3591,19 @@ $* = latin1_to_utf8($*)
 .fi
 .if n \{\
 .RE
+.SS "leftpad"
+.if n \{\
+.RS 0
+.\}
+.nf
+ (class=string #args=3) Left-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first.
+Examples:
+leftpad("abcdefg", 10 , "*") gives "***abcdefg".
+leftpad("abcdefg", 10 , "XY") gives "XYabcdefg".
+leftpad("1234567", 10 , "0") gives "0001234567".
+.fi
+.if n \{\
+.RE
 .SS "length"
 .if n \{\
 .RS 0
@@ -3831,6 +3844,19 @@ regextract_or_else("index a999 file", "[a-z][a-z][0-9][0-9]", "nonesuch") gives
 .fi
 .if n \{\
 .RE
+.SS "rightpad"
+.if n \{\
+.RS 0
+.\}
+.nf
+ (class=string #args=3) Right-pads first argument to at most the specified length (second, integer argument) using specified pad value (third, string argument). If the first argument is not a string, it will be stringified first.
+Examples:
+rightpad("abcdefg", 10 , "*") gives "abcdefg***".
+rightpad("abcdefg", 10 , "XY") gives "abcdefgXY".
+rightpad("1234567", 10 , "0") gives "1234567000".
+.fi
+.if n \{\
+.RE
 .SS "round"
 .if n \{\
 .RS 0
diff --git a/test/cases/dsl-leftpad-rightpad/L001/cmd b/test/cases/dsl-leftpad-rightpad/L001/cmd
new file mode 100644
index 000000000..661aaaddd
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L001/cmd
@@ -0,0 +1 @@
+mlr --from test/input/abixy --d2p  put -f ${CASEDIR}/mlr
diff --git a/test/cases/dsl-leftpad-rightpad/L001/experr b/test/cases/dsl-leftpad-rightpad/L001/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/dsl-leftpad-rightpad/L001/expout b/test/cases/dsl-leftpad-rightpad/L001/expout
new file mode 100644
index 000000000..bb525f584
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L001/expout
@@ -0,0 +1,11 @@
+a     b   i  x          y
+**pan pan 1  0.34679014 0.72680286
+**eks pan 2  0.75867996 0.52215111
+**wye wye 3  0.20460331 0.33831853
+**eks wye 4  0.38139939 0.13418874
+**wye pan 5  0.57328892 0.86362447
+**zee pan 6  0.52712616 0.49322129
+**eks zee 7  0.61178406 0.18788492
+**zee wye 8  0.59855401 0.97618139
+**hat wye 9  0.03144188 0.74955076
+**pan wye 10 0.50262601 0.95261836
diff --git a/test/cases/dsl-leftpad-rightpad/L001/mlr b/test/cases/dsl-leftpad-rightpad/L001/mlr
new file mode 100644
index 000000000..83f7a545c
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L001/mlr
@@ -0,0 +1 @@
+$a = leftpad($a, 5, "*")
diff --git a/test/cases/dsl-leftpad-rightpad/L002/cmd b/test/cases/dsl-leftpad-rightpad/L002/cmd
new file mode 100644
index 000000000..661aaaddd
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L002/cmd
@@ -0,0 +1 @@
+mlr --from test/input/abixy --d2p  put -f ${CASEDIR}/mlr
diff --git a/test/cases/dsl-leftpad-rightpad/L002/experr b/test/cases/dsl-leftpad-rightpad/L002/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/dsl-leftpad-rightpad/L002/expout b/test/cases/dsl-leftpad-rightpad/L002/expout
new file mode 100644
index 000000000..a575e8d80
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L002/expout
@@ -0,0 +1,11 @@
+a   b   i     x          y
+pan pan 00001 0.34679014 0.72680286
+eks pan 00002 0.75867996 0.52215111
+wye wye 00003 0.20460331 0.33831853
+eks wye 00004 0.38139939 0.13418874
+wye pan 00005 0.57328892 0.86362447
+zee pan 00006 0.52712616 0.49322129
+eks zee 00007 0.61178406 0.18788492
+zee wye 00008 0.59855401 0.97618139
+hat wye 00009 0.03144188 0.74955076
+pan wye 00010 0.50262601 0.95261836
diff --git a/test/cases/dsl-leftpad-rightpad/L002/mlr b/test/cases/dsl-leftpad-rightpad/L002/mlr
new file mode 100644
index 000000000..5923e74ae
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L002/mlr
@@ -0,0 +1 @@
+$i = leftpad($i, 5, "0")
diff --git a/test/cases/dsl-leftpad-rightpad/L003/cmd b/test/cases/dsl-leftpad-rightpad/L003/cmd
new file mode 100644
index 000000000..661aaaddd
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L003/cmd
@@ -0,0 +1 @@
+mlr --from test/input/abixy --d2p  put -f ${CASEDIR}/mlr
diff --git a/test/cases/dsl-leftpad-rightpad/L003/experr b/test/cases/dsl-leftpad-rightpad/L003/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/dsl-leftpad-rightpad/L003/expout b/test/cases/dsl-leftpad-rightpad/L003/expout
new file mode 100644
index 000000000..a575e8d80
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L003/expout
@@ -0,0 +1,11 @@
+a   b   i     x          y
+pan pan 00001 0.34679014 0.72680286
+eks pan 00002 0.75867996 0.52215111
+wye wye 00003 0.20460331 0.33831853
+eks wye 00004 0.38139939 0.13418874
+wye pan 00005 0.57328892 0.86362447
+zee pan 00006 0.52712616 0.49322129
+eks zee 00007 0.61178406 0.18788492
+zee wye 00008 0.59855401 0.97618139
+hat wye 00009 0.03144188 0.74955076
+pan wye 00010 0.50262601 0.95261836
diff --git a/test/cases/dsl-leftpad-rightpad/L003/mlr b/test/cases/dsl-leftpad-rightpad/L003/mlr
new file mode 100644
index 000000000..30cb4f547
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L003/mlr
@@ -0,0 +1 @@
+$i = leftpad($i, 5, 0)
diff --git a/test/cases/dsl-leftpad-rightpad/L004/cmd b/test/cases/dsl-leftpad-rightpad/L004/cmd
new file mode 100644
index 000000000..661aaaddd
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L004/cmd
@@ -0,0 +1 @@
+mlr --from test/input/abixy --d2p  put -f ${CASEDIR}/mlr
diff --git a/test/cases/dsl-leftpad-rightpad/L004/experr b/test/cases/dsl-leftpad-rightpad/L004/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/dsl-leftpad-rightpad/L004/expout b/test/cases/dsl-leftpad-rightpad/L004/expout
new file mode 100644
index 000000000..b8ac13481
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L004/expout
@@ -0,0 +1,11 @@
+a   b   i  x          y
+pan pan 1  0.34679014 0.72680286
+eks pan 2  0.75867996 0.52215111
+wye wye 3  0.20460331 0.33831853
+eks wye 4  0.38139939 0.13418874
+wye pan 5  0.57328892 0.86362447
+zee pan 6  0.52712616 0.49322129
+eks zee 7  0.61178406 0.18788492
+zee wye 8  0.59855401 0.97618139
+hat wye 9  0.03144188 0.74955076
+pan wye 10 0.50262601 0.95261836
diff --git a/test/cases/dsl-leftpad-rightpad/L004/mlr b/test/cases/dsl-leftpad-rightpad/L004/mlr
new file mode 100644
index 000000000..78c5f3949
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L004/mlr
@@ -0,0 +1 @@
+$a = leftpad($a, 2, "X")
diff --git a/test/cases/dsl-leftpad-rightpad/L005/cmd b/test/cases/dsl-leftpad-rightpad/L005/cmd
new file mode 100644
index 000000000..661aaaddd
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L005/cmd
@@ -0,0 +1 @@
+mlr --from test/input/abixy --d2p  put -f ${CASEDIR}/mlr
diff --git a/test/cases/dsl-leftpad-rightpad/L005/experr b/test/cases/dsl-leftpad-rightpad/L005/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/dsl-leftpad-rightpad/L005/expout b/test/cases/dsl-leftpad-rightpad/L005/expout
new file mode 100644
index 000000000..d8647b852
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L005/expout
@@ -0,0 +1,11 @@
+a         b   i  x          y
+XYXYXYpan pan 1  0.34679014 0.72680286
+XYXYXYeks pan 2  0.75867996 0.52215111
+XYXYXYwye wye 3  0.20460331 0.33831853
+XYXYXYeks wye 4  0.38139939 0.13418874
+XYXYXYwye pan 5  0.57328892 0.86362447
+XYXYXYzee pan 6  0.52712616 0.49322129
+XYXYXYeks zee 7  0.61178406 0.18788492
+XYXYXYzee wye 8  0.59855401 0.97618139
+XYXYXYhat wye 9  0.03144188 0.74955076
+XYXYXYpan wye 10 0.50262601 0.95261836
diff --git a/test/cases/dsl-leftpad-rightpad/L005/mlr b/test/cases/dsl-leftpad-rightpad/L005/mlr
new file mode 100644
index 000000000..b79b32316
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/L005/mlr
@@ -0,0 +1 @@
+$a = leftpad($a, 10, "XY")
diff --git a/test/cases/dsl-leftpad-rightpad/R001/cmd b/test/cases/dsl-leftpad-rightpad/R001/cmd
new file mode 100644
index 000000000..661aaaddd
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R001/cmd
@@ -0,0 +1 @@
+mlr --from test/input/abixy --d2p  put -f ${CASEDIR}/mlr
diff --git a/test/cases/dsl-leftpad-rightpad/R001/experr b/test/cases/dsl-leftpad-rightpad/R001/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/dsl-leftpad-rightpad/R001/expout b/test/cases/dsl-leftpad-rightpad/R001/expout
new file mode 100644
index 000000000..e48239d38
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R001/expout
@@ -0,0 +1,11 @@
+a     b   i  x          y
+pan** pan 1  0.34679014 0.72680286
+eks** pan 2  0.75867996 0.52215111
+wye** wye 3  0.20460331 0.33831853
+eks** wye 4  0.38139939 0.13418874
+wye** pan 5  0.57328892 0.86362447
+zee** pan 6  0.52712616 0.49322129
+eks** zee 7  0.61178406 0.18788492
+zee** wye 8  0.59855401 0.97618139
+hat** wye 9  0.03144188 0.74955076
+pan** wye 10 0.50262601 0.95261836
diff --git a/test/cases/dsl-leftpad-rightpad/R001/mlr b/test/cases/dsl-leftpad-rightpad/R001/mlr
new file mode 100644
index 000000000..3bbd1cecf
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R001/mlr
@@ -0,0 +1 @@
+$a = rightpad($a, 5, "*")
diff --git a/test/cases/dsl-leftpad-rightpad/R002/cmd b/test/cases/dsl-leftpad-rightpad/R002/cmd
new file mode 100644
index 000000000..661aaaddd
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R002/cmd
@@ -0,0 +1 @@
+mlr --from test/input/abixy --d2p  put -f ${CASEDIR}/mlr
diff --git a/test/cases/dsl-leftpad-rightpad/R002/experr b/test/cases/dsl-leftpad-rightpad/R002/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/dsl-leftpad-rightpad/R002/expout b/test/cases/dsl-leftpad-rightpad/R002/expout
new file mode 100644
index 000000000..6175c79f1
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R002/expout
@@ -0,0 +1,11 @@
+a   b   i     x          y
+pan pan 10000 0.34679014 0.72680286
+eks pan 20000 0.75867996 0.52215111
+wye wye 30000 0.20460331 0.33831853
+eks wye 40000 0.38139939 0.13418874
+wye pan 50000 0.57328892 0.86362447
+zee pan 60000 0.52712616 0.49322129
+eks zee 70000 0.61178406 0.18788492
+zee wye 80000 0.59855401 0.97618139
+hat wye 90000 0.03144188 0.74955076
+pan wye 10000 0.50262601 0.95261836
diff --git a/test/cases/dsl-leftpad-rightpad/R002/mlr b/test/cases/dsl-leftpad-rightpad/R002/mlr
new file mode 100644
index 000000000..143845026
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R002/mlr
@@ -0,0 +1 @@
+$i = rightpad($i, 5, "0")
diff --git a/test/cases/dsl-leftpad-rightpad/R003/cmd b/test/cases/dsl-leftpad-rightpad/R003/cmd
new file mode 100644
index 000000000..661aaaddd
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R003/cmd
@@ -0,0 +1 @@
+mlr --from test/input/abixy --d2p  put -f ${CASEDIR}/mlr
diff --git a/test/cases/dsl-leftpad-rightpad/R003/experr b/test/cases/dsl-leftpad-rightpad/R003/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/dsl-leftpad-rightpad/R003/expout b/test/cases/dsl-leftpad-rightpad/R003/expout
new file mode 100644
index 000000000..6175c79f1
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R003/expout
@@ -0,0 +1,11 @@
+a   b   i     x          y
+pan pan 10000 0.34679014 0.72680286
+eks pan 20000 0.75867996 0.52215111
+wye wye 30000 0.20460331 0.33831853
+eks wye 40000 0.38139939 0.13418874
+wye pan 50000 0.57328892 0.86362447
+zee pan 60000 0.52712616 0.49322129
+eks zee 70000 0.61178406 0.18788492
+zee wye 80000 0.59855401 0.97618139
+hat wye 90000 0.03144188 0.74955076
+pan wye 10000 0.50262601 0.95261836
diff --git a/test/cases/dsl-leftpad-rightpad/R003/mlr b/test/cases/dsl-leftpad-rightpad/R003/mlr
new file mode 100644
index 000000000..febc0efef
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R003/mlr
@@ -0,0 +1 @@
+$i = rightpad($i, 5, 0)
diff --git a/test/cases/dsl-leftpad-rightpad/R004/cmd b/test/cases/dsl-leftpad-rightpad/R004/cmd
new file mode 100644
index 000000000..661aaaddd
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R004/cmd
@@ -0,0 +1 @@
+mlr --from test/input/abixy --d2p  put -f ${CASEDIR}/mlr
diff --git a/test/cases/dsl-leftpad-rightpad/R004/experr b/test/cases/dsl-leftpad-rightpad/R004/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/dsl-leftpad-rightpad/R004/expout b/test/cases/dsl-leftpad-rightpad/R004/expout
new file mode 100644
index 000000000..b8ac13481
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R004/expout
@@ -0,0 +1,11 @@
+a   b   i  x          y
+pan pan 1  0.34679014 0.72680286
+eks pan 2  0.75867996 0.52215111
+wye wye 3  0.20460331 0.33831853
+eks wye 4  0.38139939 0.13418874
+wye pan 5  0.57328892 0.86362447
+zee pan 6  0.52712616 0.49322129
+eks zee 7  0.61178406 0.18788492
+zee wye 8  0.59855401 0.97618139
+hat wye 9  0.03144188 0.74955076
+pan wye 10 0.50262601 0.95261836
diff --git a/test/cases/dsl-leftpad-rightpad/R004/mlr b/test/cases/dsl-leftpad-rightpad/R004/mlr
new file mode 100644
index 000000000..d4fbe9dae
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R004/mlr
@@ -0,0 +1 @@
+$a = rightpad($a, 2, "X")
diff --git a/test/cases/dsl-leftpad-rightpad/R005/cmd b/test/cases/dsl-leftpad-rightpad/R005/cmd
new file mode 100644
index 000000000..661aaaddd
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R005/cmd
@@ -0,0 +1 @@
+mlr --from test/input/abixy --d2p  put -f ${CASEDIR}/mlr
diff --git a/test/cases/dsl-leftpad-rightpad/R005/experr b/test/cases/dsl-leftpad-rightpad/R005/experr
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/cases/dsl-leftpad-rightpad/R005/expout b/test/cases/dsl-leftpad-rightpad/R005/expout
new file mode 100644
index 000000000..13ff61ac8
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R005/expout
@@ -0,0 +1,11 @@
+a         b   i  x          y
+panXYXYXY pan 1  0.34679014 0.72680286
+eksXYXYXY pan 2  0.75867996 0.52215111
+wyeXYXYXY wye 3  0.20460331 0.33831853
+eksXYXYXY wye 4  0.38139939 0.13418874
+wyeXYXYXY pan 5  0.57328892 0.86362447
+zeeXYXYXY pan 6  0.52712616 0.49322129
+eksXYXYXY zee 7  0.61178406 0.18788492
+zeeXYXYXY wye 8  0.59855401 0.97618139
+hatXYXYXY wye 9  0.03144188 0.74955076
+panXYXYXY wye 10 0.50262601 0.95261836
diff --git a/test/cases/dsl-leftpad-rightpad/R005/mlr b/test/cases/dsl-leftpad-rightpad/R005/mlr
new file mode 100644
index 000000000..1e2ded43d
--- /dev/null
+++ b/test/cases/dsl-leftpad-rightpad/R005/mlr
@@ -0,0 +1 @@
+$a = rightpad($a, 10, "XY")