Skip to content

Commit 8872100

Browse files
Merge pull request #377 from ballerina-platform/api
Add new APIs
2 parents 1ce8276 + a0ddf00 commit 8872100

File tree

8 files changed

+649
-48
lines changed

8 files changed

+649
-48
lines changed

ballerina/Ballerina.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
org = "ballerina"
33
name = "regex"
4-
version = "1.2.1"
4+
version = "1.2.2"
55
authors = ["Ballerina"]
66
keywords = ["regex", "string", "regular expressions"]
77
repository = "https://github.com/ballerina-platform/module-ballerina-regex"

ballerina/Dependencies.toml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,24 @@ modules = [
1414
{org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"}
1515
]
1616

17+
[[package]]
18+
org = "ballerina"
19+
name = "lang.string"
20+
version = "0.0.0"
21+
dependencies = [
22+
{org = "ballerina", name = "jballerina.java"}
23+
]
24+
modules = [
25+
{org = "ballerina", packageName = "lang.string", moduleName = "lang.string"}
26+
]
27+
1728
[[package]]
1829
org = "ballerina"
1930
name = "regex"
20-
version = "1.2.1"
31+
version = "1.2.2"
2132
dependencies = [
2233
{org = "ballerina", name = "jballerina.java"},
34+
{org = "ballerina", name = "lang.string"},
2335
{org = "ballerina", name = "test"}
2436
]
2537
modules = [

ballerina/natives.bal

Lines changed: 164 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
// under the License.
1616

1717
import 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
70109
public 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.
98190
isolated 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-
110196
isolated 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

122208
isolated 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

Comments
 (0)