@@ -137,6 +137,17 @@ public enum Function {
137137 SimpleType .STRING ,
138138 SimpleType .STRING )),
139139 CelFunctionBinding .from ("string_lower_ascii" , String .class , Ascii ::toLowerCase )),
140+ QUOTE (
141+ CelFunctionDecl .newFunctionDeclaration (
142+ "strings.quote" ,
143+ CelOverloadDecl .newGlobalOverload (
144+ "strings_quote" ,
145+ "Takes the given string and makes it safe to print (without any formatting"
146+ + " due to escape sequences). If any invalid UTF-8 characters are"
147+ + " encountered, they are replaced with \\ uFFFD." ,
148+ SimpleType .STRING ,
149+ ImmutableList .of (SimpleType .STRING ))),
150+ CelFunctionBinding .from ("strings_quote" , String .class , CelStringExtensions ::quote )),
140151 REPLACE (
141152 CelFunctionDecl .newFunctionDeclaration (
142153 "replace" ,
@@ -164,6 +175,16 @@ public enum Function {
164175 "string_replace_string_string_int" ,
165176 ImmutableList .of (String .class , String .class , String .class , Long .class ),
166177 CelStringExtensions ::replace )),
178+ REVERSE (
179+ CelFunctionDecl .newFunctionDeclaration (
180+ "reverse" ,
181+ CelOverloadDecl .newMemberOverload (
182+ "string_reverse" ,
183+ "Returns a new string whose characters are the same as the target string,"
184+ + " only formatted in reverse order." ,
185+ SimpleType .STRING ,
186+ SimpleType .STRING )),
187+ CelFunctionBinding .from ("string_reverse" , String .class , CelStringExtensions ::reverse )),
167188 SPLIT (
168189 CelFunctionDecl .newFunctionDeclaration (
169190 "split" ,
@@ -449,6 +470,57 @@ private static Long lastIndexOf(CelCodePointArray str, CelCodePointArray substr,
449470 return -1L ;
450471 }
451472
473+ private static String quote (String s ) {
474+ StringBuilder sb = new StringBuilder (s .length () + 2 );
475+ sb .append ('"' );
476+ for (int i = 0 ; i < s .length (); ) {
477+ int codePoint = s .codePointAt (i );
478+ if (!Character .isValidCodePoint (codePoint )
479+ || Character .isLowSurrogate (s .charAt (i ))
480+ || (Character .isHighSurrogate (s .charAt (i ))
481+ && (i + 1 >= s .length () || !Character .isLowSurrogate (s .charAt (i + 1 ))))) {
482+ sb .append ('\uFFFD' );
483+ i ++;
484+ continue ;
485+ }
486+ switch (codePoint ) {
487+ case '\u0007' :
488+ sb .append ("\\ a" );
489+ break ;
490+ case '\b' :
491+ sb .append ("\\ b" );
492+ break ;
493+ case '\f' :
494+ sb .append ("\\ f" );
495+ break ;
496+ case '\n' :
497+ sb .append ("\\ n" );
498+ break ;
499+ case '\r' :
500+ sb .append ("\\ r" );
501+ break ;
502+ case '\t' :
503+ sb .append ("\\ t" );
504+ break ;
505+ case '\u000B' :
506+ sb .append ("\\ v" );
507+ break ;
508+ case '\\' :
509+ sb .append ("\\ \\ " );
510+ break ;
511+ case '"' :
512+ sb .append ("\\ \" " );
513+ break ;
514+ default :
515+ sb .appendCodePoint (codePoint );
516+ break ;
517+ }
518+ i += Character .charCount (codePoint );
519+ }
520+ sb .append ('"' );
521+ return sb .toString ();
522+ }
523+
452524 private static String replaceAll (Object [] objects ) {
453525 return replace ((String ) objects [0 ], (String ) objects [1 ], (String ) objects [2 ], -1 );
454526 }
@@ -504,6 +576,10 @@ private static String replace(String text, String searchString, String replaceme
504576 return sb .append (textCpa .slice (start , textCpa .length ())).toString ();
505577 }
506578
579+ private static String reverse (String s ) {
580+ return new StringBuilder (s ).reverse ().toString ();
581+ }
582+
507583 private static List <String > split (String str , String separator ) {
508584 return split (str , separator , Integer .MAX_VALUE );
509585 }
0 commit comments