summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2015-05-18 23:02:11 -0500
committerNicolas Williams <nico@cryptonector.com>2015-05-18 23:02:11 -0500
commitcbdaeb4062cf97de2479f9c825e19088be603e88 (patch)
tree6039ed724e0a3026b6a653b7a8d31aef2a9b17b2
parentcf1306f469d0efb178f567f0b43e9af0435593ca (diff)
Fix gsub, add gsub/3 (fix #782)
-rw-r--r--builtin.c43
-rw-r--r--docs/content/3.manual/manual.yml2
-rw-r--r--tests/all.test4
3 files changed, 31 insertions, 18 deletions
diff --git a/builtin.c b/builtin.c
index 348c965c..cc295bff 100644
--- a/builtin.c
+++ b/builtin.c
@@ -1354,24 +1354,33 @@ static const char* const jq_builtins[] = {
" | $in[0:$r.offset] + s + $in[$r.offset+$r.length:]"
" end ;",
//
+ // If s contains capture variables, then create a capture object and pipe it to s
+ "def sub($re; s; flags):"
+ " def subg: explode | select(. != 103) | implode;"
+ // # "fla" should be flags with all occurrences of g removed; gs should be non-nil if flags has a g
+ " def sub1(fla; gs):"
+ " def mysub:"
+ " . as $in"
+ " | [match($re; fla)]"
+ " | if length == 0 then $in"
+ " else .[0] as $edit"
+ " | ($edit | .offset + .length) as $len"
+ // # create the "capture" object:
+ " | reduce ( $edit | .captures | .[] | select(.name != null) | { (.name) : .string } ) as $pair"
+ " ({}; . + $pair)"
+ " | $in[0:$edit.offset]"
+ " + s"
+ " + ($in[$len:] | if gs then mysub else . end)"
+ " end ;"
+ " mysub ;"
+ " (flags | index(\"g\")) as $gs"
+ " | (flags | if $gs then subg else . end) as $fla"
+ " | sub1($fla; $gs);",
+ //
+ "def sub($re; s): sub($re; s; \"\");",
// repeated substitution of re (which may contain named captures)
- "def gsub($re; s; flags):"
- // # _stredit(edits;s) - s is the \"to\" string, which might contain capture variables,
- // # so if an edit contains captures, then create the capture object and pipe it to s
- " def _stredit(edits; s):"
- " if (edits|length) == 0 then ."
- " else . as $in"
- " | (edits|length -1) as $l"
- " | (edits[$l]) as $edit"
- // # create the \"capture\" object:
- " | ($edit | reduce ( $edit | .captures | .[] | select(.name != null) | { (.name) : .string } ) as $pair"
- " ({}; . + $pair) )"
- " | if . == {} then $in | .[0:$edit.offset]+s+.[$edit.offset+$edit.length:] | _stredit(edits[0:$l]; s)"
- " else (if $l == 0 then \"\" else ($in | _stredit(edits[0:$l]; s)) end) + (. | s)"
- " end"
- " end ;"
- " [match($re; flags + \"g\")] as $edits | _stredit($edits; s) ;",
- "def gsub($re; s): gsub($re; s; \"\");",
+ "def gsub($re; s; flags): sub($re; s; flags + \"g\");",
+ "def gsub($re; s): sub($re; s; \"g\");",
//#######################################################################
// range/3, with a `by` expression argument
diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml
index 48d3de19..78967066 100644
--- a/docs/content/3.manual/manual.yml
+++ b/docs/content/3.manual/manual.yml
@@ -2045,7 +2045,7 @@ sections:
output: '"ZabcZabc"'
- - title: "`gsub(regex; string)`"
+ - title: "`gsub(regex; string)`, `gsub(regex; string; flags)`"
body: |
`gsub` is like `sub` but all the non-overlapping occurrences of the regex are
diff --git a/tests/all.test b/tests/all.test
index 075e8471..106afaa4 100644
--- a/tests/all.test
+++ b/tests/all.test
@@ -892,6 +892,10 @@ sub("^(?<head>.)"; "Head=\(.head) Tail=")
["a,b, c, d, e,f",", a,b, c, d, e,f, "]
["a,b:c:d:e,f",":a,b:c:d:e,f:"]
+gsub("(?<d>\\d)"; ":\(.d);")
+"a1b2"
+"a:1;b:2;"
+
[.[] | scan(", ")]
["a,b, c, d, e,f",", a,b, c, d, e,f, "]
[", ",", ",", ",", ",", ",", ",", ",", "]