In a Flutter application, I need to check if a string matches a specific RegEx. However, the RegEx I copied from the JavaScript version of the app always returns false in the Flutter app. I verified on regexr that the RegEx is valid, and this very RegEx is already being used in the JavaScript application, so it should be correct.
Any help is appreciated!
RegEx : /^WS{1,2}:\/\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:56789/i
Test Code :
RegExp regExp = new RegExp(
r"/^WS{1,2}:\/\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:56789/i",
caseSensitive: false,
multiLine: false,
);
print("allMatches : "+regExp.allMatches("WS://127.0.0.1:56789").toString());
print("firstMatch : "+regExp.firstMatch("WS://127.0.0.1:56789").toString());
print("hasMatch : "+regExp.hasMatch("WS://127.0.0.1:56789").toString());
print("stringMatch : "+regExp.stringMatch("WS://127.0.0.1:56789").toString());
Output :
allMatches : ()
firstMatch : null
hasMatch : false
stringMatch : null
This is a more general answer for future viewers.
Regex in Dart works much like other languages. You use the RegExp class to define a matching pattern. Then use hasMatch() to test the pattern on a string.
Examples
Alphanumeric
final alphanumeric = RegExp(r'^[a-zA-Z0-9]+$');
alphanumeric.hasMatch('abc123'); // true
alphanumeric.hasMatch('abc123%'); // false
Hex colors
RegExp hexColor = RegExp(r'^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$');
hexColor.hasMatch('#3b5'); // true
hexColor.hasMatch('#FF7723'); // true
hexColor.hasMatch('#000000z'); // false
Extracting text
final myString = '25F8..25FF ; Common # Sm [8] UPPER LEFT TRIANGLE';
// find a variable length hex value at the beginning of the line
final regexp = RegExp(r'^[0-9a-fA-F]+');
// find the first match though you could also do `allMatches`
final match = regexp.firstMatch(myString);
// group(0) is the full matched text
// if your regex had groups (using parentheses) then you could get the
// text from them by using group(1), group(2), etc.
final matchedText = match?.group(0); // 25F8
There are some more examples here.
See also:
Extracting text from a string with regex groups in Dart
I think you tried to include options in the raw expression string while you already have it as parameters to RegEx ( /i for case insensitivity is declared as caseSensitive: false).
// Removed /i at the end
// Removed / in front - Thanks to Günter for warning
RegExp regExp = new RegExp(
r"^WS{1,2}:\/\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:56789",
caseSensitive: false,
multiLine: false,
);
print("allMatches : "+regExp.allMatches("WS://127.0.0.1:56789").toString());
print("firstMatch : "+regExp.firstMatch("WS://127.0.0.1:56789").toString());
print("hasMatch : "+regExp.hasMatch("WS://127.0.0.1:56789").toString());
print("stringMatch : "+regExp.stringMatch("WS://127.0.0.1:56789").toString());
Gives:
allMatches : (Instance of '_MatchImplementation')
firstMatch : Instance of '_MatchImplementation'
hasMatch : true
stringMatch : WS://127.0.0.1:56789
Related
This question already has an answer here:
How to put all regex matches into a string list
(1 answer)
Closed 1 year ago.
I want to return a pattern through regEx in flutter every time it' found, I tested using the Regex operation it worked on the same string, returning the match after that included match 'text:' to '}' letters, but it does not print the matches in the flutter application.
The code I am using:
String myString = '{boundingBox: 150,39,48,25, text: PM},';
RegExp exp = RegExp(r"text:(.+?(?=}))");
print("allMatches : "+exp.allMatches(myString).toString());
The output print statement is printing I/flutter ( 5287): allMatches : (Instance of '_RegExpMatch', Instance of '_RegExpMatch')
instead of text: PM
Following is the screenshot of how it is parsing on regexr.com
Instead of using a non greedy match with a lookahead, I would suggest using a negated character class matching any char except } in capture group 1, and match the } after the group to prevent some backtracking.
\b(text:[^}]+)}
You can loop the result from allMatches and print group 1:
String myString = '{boundingBox: 150,39,48,25, text: PM},';
RegExp exp = RegExp(r"\b(text:[^}]+)}");
for (var m in exp.allMatches(myString)) {
print(m[1]);
}
Output
text: PM
You need to use map method to retrieve the string from the matches:
String myString = '{boundingBox: 150,39,48,25, text: PM},';
RegExp exp = RegExp(r"text:(.+?(?=}))");
final matches = exp.allMatches(myString).map((m) => m.group(0)).toString();
print("allMatches : $matches");
I'm filtering list like this but i think there should be better approach to filter list inside where bloc it is not allowing me to declare variable. is there any other way to achieve the same
var cc = contactsAll
.where(
(i) =>
regularExpression(i.displayName, 'dev') ||
regularExpression(i.displayName, 'soft') ||
regularExpression(i.displayName, 'angular') ||
regularExpression(i.displayName, 'java')
)
.toList();
my expression filter function
bool regularExpression(String stringg, String search) {
RegExp exp = new RegExp(
"\\b" + search + "\\b",
caseSensitive: false,
);
return exp.hasMatch(stringg);
}
Thanks in advance
You may build the pattern dynamically:
var keys = ['dev', 'soft', 'angular', 'java'];
var regex = new RegExp("\\b(?:${keys.join('|')})\\b", caseSensitive: false);
var contactsAll = ['No match', 'I like java', 'I like javascript'];
var cc = contactsAll.where( (i) => regex.hasMatch(i) ).toList();
print(cc); // => [I like java]
The regex will look like \b(?:dev|soft|angular|java)\b and will match any of the keywords inside the non-capturing group as a whole word due to the \b word boundaries. See the regex demo.
If the keys can contain special characters, but you still need a whole word search, you need to escape all special characters and use either unambiguous boundaries
var regex = new RegExp("(?:^|\\W)(?:${keys.map((val) => val.replaceAll(new RegExp(r'[-\/\\^$*+?.()|[\]{}]'), r'\\$&')).join('|')})(?!\\w)", caseSensitive: false);
This results in a (?:^|\W)(?:dev|soft|angular|java)(?!\w) pattern (see demo) where (?:^|\W) matches start of string or a non-word char and (?!\w) requires the absense of a word char immediately to the right of the current location.
The .map((val) => val.replaceAll(new RegExp(r'[-\/\\^$*+?.()|[\]{}]'), r'\\$&')) part escapes the literal part for use within regex.
Or whitespace boundaries:
var regex = new RegExp("(?:^|\\s)(?:${keys.map((val) => val.replaceAll(new RegExp(r'[-\/\\^$*+?.()|[\]{}]'), r'\\$&')).join('|')})(?!\\S)", caseSensitive: false);
This results in a (?:^|\s)(?:dev|soft|angular|java)(?!\S) pattern where (?:^|\s) matches start of string or a whitespace char and (?!\S) requires the absense of a non-whitespace char immediately to the right of the current location.
See the regex demo.
Without creating a function, you can use the contains method on your displayName like this :
var cc = contactsAll
.where((i) =>
i.displayName.contains(RegExp('\\bdev\\b')) ||
i.displayName.contains(RegExp('\\bsoft\\b')) ||
i.displayName.contains(RegExp('\\bangular\\b')) ||
i.displayName.contains(RegExp('\\bjava\\b')),)
.toList();
I have regexp code like below (I'm using VerbalExpression dart plugin ), My purpose is to check that a string starts with "36", followed by "01", "02", or "03". After that can be anything as long as the whole string is 16 characters long.
var regex = VerbalExpression()
..startOfLine()
..then("36")
..then("01")
..or("02")
..anythingBut(" ")
..endOfLine();
String nik1 = "3601999999999999";
String nik2 = "3602999999999999";
String nik3 = "3603999999999999";
print('result : ${regex.hasMatch(nik1)}');
print('Hasil : ${regex.hasMatch(nik2)}');
print('Hasil : ${regex.hasMatch(nik3)}');
my code only true for nik1 and nik2, however i want true for nik3, I noticed that i can't put or() after or() for multiple check, it just give me all false result, how do i achieve that?
I'm not familiar with VerbalExpression, but a RegExp that does this is straightforward enough.
const pattern = r'^36(01|02|03)\S{12}$';
void main() {
final regex = RegExp(pattern);
print(regex.hasMatch('3601999999999999')); // true
print(regex.hasMatch('3602999999999999')); // true
print(regex.hasMatch('3603999999999999')); // true
print(regex.hasMatch('360199999999999')); // false
print(regex.hasMatch('3600999999999999')); // false
print(regex.hasMatch('36019999999999999')); // false
}
Pattern explanation:
The r prefix means dart will interpret it as a raw string ("$" and "\" are not treated as special).
The ^ and $ represent the beginning and end of the string, so it will only match the whole string and cannot find matches from just part of the string.
(01|02|03) "01" or "02" or "03". | means OR. Wrapping it in parentheses lets it know where to stop the OR.
\S matches any non-whitespace character.
{12} means the previous thing must be repeated 12 times, so \S{12} means any 12 non-whitespace characters.
Based on this example: http://example.com/cat1/tag/this%20is%20page/cat2, i need to make a regex to get /tag/<nextSegment> only if this pattern is followed or preceded by other segments, not if is alone.
The result that i need is always: http://example.com/tag/<fowardSegment> only if /tag/<fowardSegment> is preceded or followed from other segments or characters not allowed.
I tried with this regex: ((?:/[A-Za-z0-9-]+)+)?(/tag/[A-Za-z0-9-%]+)+(/.*)? but the pattern is catched also when it's alone (as you can see last example string in link).
Perhaps you want is this: /(?<=https?:\/\/.*)((?:\/[\w]+)*)((?:\/tag)(?:\/[\w%?=.-]+){2,})$/
EDIT
As I was made aware in the comments below of the extra ones that need matching:
/(?<=https?:\/\/.*|[\w_.]+)(?:((?:\/[\w]+)+)((?:\/tag)(?:\/[\w%?=.-]+))|((?:\/[\w]+))*((?:\/tag)(?:\/[\w%?=.-]+){2,}))$/
An example usage in JS:
let regex = /(?<=https?:\/\/.*|[\w_.]+)(?:((?:\/[\w]+)+)((?:\/tag)(?:\/[\w%?=.-]+))|((?:\/[\w]+))*((?:\/tag)(?:\/[\w%?=.-]+){2,}))$/,
examples = ["http://example.com/cat1/subcat3/subcat4/tag/this%20is%20page/asdasda?start=130/asdasdasd", // #Should Match
"http://example.com/cat1/subcat3/subcat4/tag/this%20is%20pageasdasd", // Should Match
"example.it/news/tag/this%is%20n%page?adsadsadasd", // Should Match
"http://example.com/tag/thispage/asdasdasd.-?asds=", // Should Match
"http://example.com/tag/this%20is%20page/asdasd", // Should Match
"http://example.com/tag/this", // Should Not Match
"/tag/this/asdads" // Should Not Match
]
examples.forEach((example) => {
if (example.match(regex)) {
let matches = regex.exec(example),
category = matches[1] !== undefined ? matches[1] : matches[3] !== undefined ? matches[3] : "No category",
tag = matches[2] === undefined ? matches[4] : matches[2];
console.log(`Full String: "${example}"\nCategory: "${category}"\nTag: "${tag}"`)
}
})
See it on Regex101
I have tried to use what I've learnt in this post,
and now I want to compose a RegExp which checks whether a string contains digits and commas. For example, "1,2,55,2" should be ok, whereas "a,2,55,2" or "1.2,55,2" should fail test. My code:
Private Function testRegExp(str, pattern) As Boolean
Dim regEx As New RegExp
If pattern <> "" Then
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.pattern = pattern
End With
If regEx.Test(str) Then
testRegExp = True
Else
testRegExp = False
End If
Else
testRegExp = True
End If
End Function
Public Sub foo()
MsgBox testRegExp("2.d", "[0-9]+")
End Sub
MsgBox yields true instead of false. What's the problem ?
Your regex matches a partial string, it matches a digit in all 55,2, a,2,55,2, 1.2,55,2 input strings.
Use anchors ^ and $ to enforce a full string match and add a comma to the character class as you say you want to match strings that only contain digits and commas:
MsgBox testRegExp("2.d", "^[0-9,]*$")
^ ^ ^
I also suggest using * quantifier to match 0 or more occurrences, rather than + (1 or more occurrences), but it is something you need to decide for yourself (whether you want to allow an empty string match or not).
Here is the regex demo. Note it is for PCRE regex flavor, but this regex will perform similarly in VBA.
Yes, as #Chaz suggests, if you do not need to match the string/line itself, the alternative is to match an inverse character class:
MsgBox testRegExp("2.d", "[^0-9,]")
This way, the negated character class [^0-9,] will match any character but a comma / digit, invalidating the string. If the result is True, it will mean the string contains some characters other than digits and a comma.
You can use the limited built in pattern matching for that:
function isOk(str) As boolean
for i = 1 To len(str)
if Mid$(str, i, 1) Like "[!0-9,]" then exit function
next
g = True and Len(str) > 0
end function