]> granicus.if.org Git - jq/commitdiff
Fix gsub, add gsub/3 (fix #782)
authorNicolas Williams <nico@cryptonector.com>
Tue, 19 May 2015 04:02:11 +0000 (23:02 -0500)
committerNicolas Williams <nico@cryptonector.com>
Tue, 19 May 2015 04:02:11 +0000 (23:02 -0500)
builtin.c
docs/content/3.manual/manual.yml
tests/all.test

index 348c965ce49be826aaae6f7361475a4cb1a3cb93..cc295bffaa5d3bd379cf8cbc74870cc022f4469d 100644 (file)
--- 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
index 48d3de1903f76ba15d22c4be0875f9905cae93ef..7896706647355ffbc135f14471e73c1e76221544 100644 (file)
@@ -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
index 075e847115480314ab004be5262512f93e47f865..106afaa4e701f9043dd1b73658947faf7cfb9adc 100644 (file)
@@ -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, "]
 [", ",", ",", ",", ",", ",", ",", ",", "]