1515// under the License.
1616
1717import ballerina /jballerina .java ;
18+ import ballerina /lang .'string as strings ;
1819
1920# Checks whether the given string matches the provided regex.
2021# ```ballerina
@@ -28,6 +29,36 @@ public isolated function matches(string stringToMatch, string regex) returns boo
2829 return matchesExternal (java : fromString (stringToMatch ), java : fromString (regex ));
2930}
3031
32+ # Replaces the first substring that matches the given regex with
33+ # the provided replacement string or string returned by the provided function.
34+ # ```ballerina
35+ # string result = regex:replace("Ballerina is great", "\\s+", "_");
36+ # ```
37+ #
38+ # + originalString - The original string to replace the first occurrence of the
39+ # substring that matches the provided regex
40+ # + regex - The regex to match the first substring in the `originalString` to be replaced
41+ # + replacement - The replacement string or a function to be invoked to create the new substring to be
42+ # used to replace the first match to the given regex
43+ # + startIndex - The starting index for the search
44+ # + return - The resultant string with the replaced substring
45+ public isolated function replace(string originalString , string regex , Replacement replacement ,
46+ int startIndex = 0 ) returns string {
47+ Match ? matched = search (originalString , regex , startIndex );
48+ if matched is () {
49+ return originalString ;
50+ }
51+ int index = 0 ;
52+ int length = originalString .length ();
53+ string updatedString = strings : substring (originalString , index , matched .startIndex ) +
54+ getReplacementString (matched , replacement );
55+ index = matched .endIndex ;
56+ if index < length {
57+ updatedString += strings : substring (originalString , index , length );
58+ }
59+ return updatedString ;
60+ }
61+
3162# Replaces each occurrence of the substrings, which match the provided
3263# regex from the given original string value with the
3364# provided replacement string.
@@ -38,20 +69,25 @@ public isolated function matches(string stringToMatch, string regex) returns boo
3869# + originalString - The original string to replace the occurrences of the
3970# substrings that match the provided regex
4071# + regex - The regex to match the substrings in the `originalString` , which is to be replaced
41- # + replacement - The replacement string to replace the substrings, which
42- # match the regex
72+ # + replacement - The replacement string or a function to be invoked to create the new substring to be
73+ # used to replace the first match to the given regex
4374# + return - The resultant string with the replaced substrings
44- public isolated function replaceAll(string originalString , string regex , string replacement ) returns string {
45- handle value = replaceAllExternal (java : fromString (originalString ), java : fromString (regex ),
46- java : fromString (replacement ));
47- string ? updatedString = java : toString (value );
48- if updatedString is string {
49- return updatedString ;
50- } else {
51- // Should never reach here.
52- error e = error (string ` error occurred while replacing ${regex } in ${originalString }` );
53- panic e ;
75+ public isolated function replaceAll(string originalString , string regex , Replacement replacement ) returns string {
76+ Match [] matchedArray = searchAll (originalString , regex );
77+ if matchedArray .length () == 0 {
78+ return originalString ;
79+ }
80+ string updatedString = " " ;
81+ int startIndex = 0 ;
82+ foreach Match matched in matchedArray {
83+ updatedString += strings : substring (originalString , startIndex , matched .startIndex ) +
84+ getReplacementString (matched , replacement );
85+ startIndex = matched .endIndex ;
5486 }
87+ if startIndex < originalString .length () {
88+ updatedString += strings : substring (originalString , startIndex , originalString .length ());
89+ }
90+ return updatedString ;
5591}
5692
5793# Replaces the first substring that matches the given regex with
@@ -67,17 +103,20 @@ public isolated function replaceAll(string originalString, string regex, string
67103# + replacement - The replacement string to replace the first substring, which
68104# matches the regex
69105# + return - The resultant string with the replaced substring
106+ # # Deprecated
107+ # This function will be removed in a later. Use `replace` instead.
108+ @deprecated
70109public isolated function replaceFirst(string originalString , string regex , string replacement ) returns string {
71- handle value = replaceFirstExternal (java : fromString (originalString ), java : fromString (regex ),
72- java : fromString (replacement ));
73- string ? updatedString = java : toString (value );
74- if updatedString is string {
75- return updatedString ;
76- } else {
77- // Should never reach here.
78- error e = error (string ` error occurred while replacing ${regex } in ${originalString }` );
79- panic e ;
110+ handle | error value = trap replaceFirstExternal (java : fromString (originalString ), java : fromString (regex ),
111+ java : fromString (replacement ));
112+ if value is handle {
113+ string ? updatedString = java : toString (value );
114+ if updatedString is string {
115+ return updatedString ;
116+ }
117+ panic error (string ` error occurred while replacing ${regex } in ${originalString }` );
80118 }
119+ panic error (string ` error occurred while replacing ${regex } in ${originalString }: ` + value .detail ().toString ());
81120}
82121
83122# Returns an array of strings by splitting a string using the provided
@@ -94,19 +133,66 @@ public isolated function split(string receiver, string delimiter) returns string
94133 return getBallerinaStringArray (res );
95134}
96135
136+ # Returns the first substring in str that matches the regex.
137+ # ```ballerina
138+ # regex:Match? result = regex:search("Betty Botter bought some butter but she said the butter’s bitter.",
139+ # "\\b[bB].tt[a-z]*");
140+ # ```
141+ #
142+ # + str - The string to be matched
143+ # + regex - The regex value
144+ # + startIndex - The starting index for the search
145+ # + return - a `Match` record which holds the matched substring, or nil if there is no match
146+ public isolated function search(string str , string regex , int startIndex = 0 ) returns Match ? {
147+ string extractedString = getSubstring (str , startIndex );
148+ handle matcher = getMatcher (extractedString , regex );
149+ int groupCount = getGroupCount (matcher );
150+ if isMatched (matcher ) {
151+ PartMatch [] partMatch = getPartMatch (matcher , groupCount , startIndex );
152+ Match matched = {
153+ matched : partMatch [0 ].matched ,
154+ startIndex : partMatch [0 ].startIndex ,
155+ endIndex : partMatch [0 ].endIndex ,
156+ groups : new MatchGroups (partMatch , groupCount )
157+ };
158+ return matched ;
159+ }
160+ return ();
161+ }
162+
163+ # Returns all substrings in string that match the regex.
164+ # ```ballerina
165+ # regex:Match[] result = regex:searchAll("Betty Botter bought some butter but she said the butter’s bitter.",
166+ # "\\b[bB].tt[a-z]*");
167+ # ```
168+ #
169+ # + str - The string to be matched
170+ # + regex - The regex value
171+ # + return - An array of `Match` records
172+ public isolated function searchAll(string str , string regex ) returns Match [] {
173+ handle matcher = getMatcher (str , regex );
174+ Match [] matched = [];
175+ int groupCount = getGroupCount (matcher );
176+ while isMatched (matcher ) {
177+ PartMatch [] partMatch = getPartMatch (matcher , groupCount );
178+ matched .push (
179+ {
180+ matched : partMatch [0 ].matched ,
181+ startIndex : partMatch [0 ].startIndex ,
182+ endIndex : partMatch [0 ].endIndex ,
183+ groups : new MatchGroups (partMatch , groupCount )
184+ });
185+ }
186+ return matched ;
187+ }
188+
97189// Interoperable external functions.
98190isolated function matchesExternal(handle stringToMatch , handle regex ) returns boolean = @java :Method {
99191 name : " matches" ,
100192 'class : " java.lang.String" ,
101193 paramTypes : [" java.lang.String" ]
102194} external ;
103195
104- isolated function replaceAllExternal(handle originalString , handle regex , handle replacement ) returns handle = @java :Method {
105- name : " replaceAll" ,
106- 'class : " java.lang.String" ,
107- paramTypes : [" java.lang.String" , " java.lang.String" ]
108- } external ;
109-
110196isolated function replaceFirstExternal(handle originalString , handle regex , handle replacement ) returns handle = @java :Method {
111197 name : " replaceFirst" ,
112198 'class : " java.lang.String" ,
@@ -120,7 +206,55 @@ isolated function splitExternal(handle receiver, handle delimiter) returns handl
120206} external ;
121207
122208isolated function getBallerinaStringArray(handle h ) returns string [] = @java :Method {
123- 'class : " io.ballerina.runtime.api.utils.StringUtils" ,
124- name : " fromStringArray" ,
125- paramTypes : [" [Ljava.lang.String;" ]
209+ 'class : " io.ballerina.runtime.api.utils.StringUtils" ,
210+ name : " fromStringArray" ,
211+ paramTypes : [" [Ljava.lang.String;" ]
212+ } external ;
213+
214+ isolated function getMatcherFromPattern(handle patternJObj , handle input ) returns handle = @java :Method {
215+ name : " matcher" ,
216+ 'class : " java.util.regex.Pattern"
217+ } external ;
218+
219+ isolated function isMatched(handle matcherObj ) returns boolean = @java :Method {
220+ name : " find" ,
221+ 'class : " java.util.regex.Matcher"
222+ } external ;
223+
224+ isolated function getGroup(handle matcherObj , int index ) returns handle = @java :Method {
225+ name : " group" ,
226+ 'class : " java.util.regex.Matcher" ,
227+ paramTypes : [" int" ]
228+ } external ;
229+
230+ isolated function getStartIndex(handle matcherObj ) returns int = @java :Method {
231+ name : " start" ,
232+ 'class : " java.util.regex.Matcher"
233+ } external ;
234+
235+ isolated function getEndIndex(handle matcherObj ) returns int = @java :Method {
236+ name : " end" ,
237+ 'class : " java.util.regex.Matcher"
238+ } external ;
239+
240+ isolated function regexCompile(handle regex ) returns handle = @java :Method {
241+ name : " compile" ,
242+ 'class : " java.util.regex.Pattern"
243+ } external ;
244+
245+ isolated function getGroupStartIndex(handle matcherObj , int index ) returns int = @java :Method {
246+ name : " start" ,
247+ 'class : " java.util.regex.Matcher" ,
248+ paramTypes : [" int" ]
249+ } external ;
250+
251+ isolated function getGroupEndIndex(handle matcherObj , int index ) returns int = @java :Method {
252+ name : " end" ,
253+ 'class : " java.util.regex.Matcher" ,
254+ paramTypes : [" int" ]
255+ } external ;
256+
257+ isolated function getGroupCount(handle matcherObj ) returns int = @java :Method {
258+ name : " groupCount" ,
259+ 'class : " java.util.regex.Matcher"
126260} external ;
0 commit comments