@@ -609,10 +609,11 @@ public static String leftPad(final String str, final int size, String padStr) {
609609 if (pads <= 0 ) {
610610 return str ;
611611 }
612- String padding = "" ;
612+ StringBuilder paddingSb = new StringBuilder () ;
613613 for (int i = 0 ; i < pads + 1 ; i ++) {
614- padding += padStr ;
614+ paddingSb . append ( padStr ) ;
615615 }
616+ String padding = paddingSb .toString ();
616617 return substr (padding , 0 , pads ).concat (str );
617618 }
618619
@@ -638,10 +639,11 @@ public static String rightPad(final String str, final int size, String padStr) {
638639 if (pads <= 0 ) {
639640 return str ;
640641 }
641- String padding = "" ;
642+ StringBuilder paddingSb = new StringBuilder () ;
642643 for (int i = 0 ; i < pads + 1 ; i ++) {
643- padding += padStr ;
644+ paddingSb . append ( padStr ) ;
644645 }
646+ String padding = paddingSb .toString ();
645647 return str .concat (substr (padding , 0 , pads ));
646648 }
647649
@@ -770,14 +772,21 @@ public static String join(List<String> strs, String separator) {
770772 return String .join (separator , strs );
771773 }
772774
775+ private static final Pattern DOLLAR_DOLLAR = Pattern .compile ("\\ $\\ $" );
776+ private static final Pattern DOLLAR_WITHOUT_ESCAPE = Pattern .compile ("([^\\ \\ ]|^)\\ $([^0-9^<])" );
777+ private static final Pattern DOLLAR_AT_END = Pattern .compile ("\\ $$" );
773778 static String safeReplacement (String in ) {
774779 // In JSONata and in Java the $ in the replacement test usually starts the insertion of a capturing group
775780 // In order to replace a simple $ in Java you have to escape the $ with "\$"
776781 // in JSONata you do this with a '$$'
777- // "\$" followed any character besides '<' and and digit into $ + this character
778- return in .replaceAll ("\\ $\\ $" , "\\ \\ \\ $" )
779- .replaceAll ("([^\\ \\ ]|^)\\ $([^0-9^<])" , "$1\\ \\ \\ $$2" )
780- .replaceAll ("\\ $$" , "\\ \\ \\ $" ); // allow $ at end
782+ // "\$" followed any character besides '<' and and digit into $ + this character
783+ if (!in .contains ("$" )) {
784+ return in ;
785+ }
786+ String result = DOLLAR_DOLLAR .matcher (in ).replaceAll ("\\ \\ \\ $" );
787+ result = DOLLAR_WITHOUT_ESCAPE .matcher (result ).replaceAll ("$1\\ \\ \\ $$2" );
788+ result = DOLLAR_AT_END .matcher (result ).replaceAll ("\\ \\ \\ $" );
789+ return result ;
781790 }
782791
783792 /**
@@ -813,7 +822,7 @@ static String safeReplaceAll(String s, Pattern pattern, Object _replacement) {
813822 if (!msg .contains ("No group" )) throw e ;
814823
815824 // Adjust replacement to remove the non-existing group
816- String g = "" + msg .charAt (msg .length ()-1 );
825+ String g = String . valueOf ( msg .charAt (msg .length ()-1 ) );
817826
818827 replacement = replacement .replace ("$" +g , "" );
819828 }
@@ -865,7 +874,7 @@ static String safeReplaceAllFn(String s, Pattern pattern, Object fn) {
865874
866875 /**
867876 * Safe replaceFirst
868- *
877+ *
869878 * @param s
870879 * @param pattern
871880 * @param replacement
@@ -887,7 +896,7 @@ static String safeReplaceFirst(String s, Pattern pattern, String replacement) {
887896 if (!msg .contains ("No group" )) throw e ;
888897
889898 // Adjust replacement to remove the non-existing group
890- String g = "" + msg .charAt (msg .length ()-1 );
899+ String g = String . valueOf ( msg .charAt (msg .length ()-1 ) );
891900
892901 replacement = replacement .replace ("$" +g , "" );
893902 }
@@ -909,10 +918,10 @@ public static String replace(String str, Object pattern, Object replacement, Int
909918 return safeReplaceAll (str , (Pattern )pattern , replacement );
910919 }
911920 } else {
912-
921+
913922 if (limit <0 )
914923 throw new JException ("Fourth argument of replace function must evaluate to a positive number" , 0 );
915-
924+
916925 for (int i =0 ; i <limit ; i ++)
917926 if (pattern instanceof String ) {
918927 str = str .replaceFirst ((String )pattern , (String )replacement );
@@ -963,6 +972,12 @@ public static String base64decode(String str) {
963972 }
964973 }
965974
975+ private static final Pattern PLUS = Pattern .compile ("\\ +" );
976+ private static final Pattern PERCENT_21 = Pattern .compile ("%21" );
977+ private static final Pattern PERCENT_27 = Pattern .compile ("%27" );
978+ private static final Pattern PERCENT_28 = Pattern .compile ("%28" );
979+ private static final Pattern PERCENT_29 = Pattern .compile ("%29" );
980+ private static final Pattern PERCENT_7E = Pattern .compile ("%7E" );
966981 /**
967982 * Encode a string into a component for a url
968983 * @param {String} str - String to encode
@@ -975,14 +990,20 @@ public static String encodeUrlComponent(String str) {
975990 }
976991
977992 Utils .checkUrl (str );
978-
979- return URLEncoder .encode (str , StandardCharsets .UTF_8 )
980- .replaceAll ("\\ +" , "%20" )
981- .replaceAll ("\\ %21" , "!" )
982- .replaceAll ("\\ %27" , "'" )
983- .replaceAll ("\\ %28" , "(" )
984- .replaceAll ("\\ %29" , ")" )
985- .replaceAll ("\\ %7E" , "~" );
993+
994+ String encoded = URLEncoder .encode (str , StandardCharsets .UTF_8 );
995+
996+ if (!encoded .contains ("+" ) && !encoded .contains ("%" )) {
997+ return encoded ;
998+ }
999+
1000+ encoded = PLUS .matcher (encoded ).replaceAll ("%20" );
1001+ encoded = PERCENT_21 .matcher (encoded ).replaceAll ("!" );
1002+ encoded = PERCENT_27 .matcher (encoded ).replaceAll ("'" );
1003+ encoded = PERCENT_28 .matcher (encoded ).replaceAll ("(" );
1004+ encoded = PERCENT_29 .matcher (encoded ).replaceAll (")" );
1005+ encoded = PERCENT_7E .matcher (encoded ).replaceAll ("~" );
1006+ return encoded ;
9861007 }
9871008
9881009 /**
@@ -997,7 +1018,7 @@ public static String encodeUrl(String str) {
9971018 }
9981019
9991020 Utils .checkUrl (str );
1000-
1021+
10011022 try {
10021023 // only encode query part: https://docs.jsonata.org/string-functions#encodeurl
10031024 URL url = new URL (str );
@@ -1083,7 +1104,7 @@ public static List<String> split(String str, Object pattern, Number limit) {
10831104 // $split("str", ""): Split string into characters
10841105 int l = limit !=null ? limit .intValue () : Integer .MAX_VALUE ;
10851106 for (int i =0 ; i <str .length () && i <l ; i ++) {
1086- result .add ( "" + str .charAt (i ) );
1107+ result .add (String . valueOf ( str .charAt (i )) );
10871108 }
10881109 } else {
10891110 // Quote separator string + preserve trailing empty strings (-1)
0 commit comments