ZetCode

Dart regular expressions

last modified October 18, 2026

In this article we show how to work with regular expressions in Dart.

Regular expressions are used for text searching and more advanced text manipulation. We find them in tools such as grep and sed, text editors such as vi and Emacs, and programming languages.

RegExp is used to define a regular expression. Dart regular expressions have the same syntax and semantics as JavaScript regular expressions. It is a good practice to define the patterns as raw strings (r'...') so that the backslashes are not interpreted as escape sequences by Dart.

Dart regex hasMatch

The hasMatch function checks whether the regular expression has a match in the specified string.

main.dart
void main() {
  final words = <String>['Seven', 'even', 'Maven', 'Amen', 'eleven'];
  final rx = RegExp(r'.even');

  for (final word in words) {
    if (rx.hasMatch(word)) {
      print('$word does match');
    } else {
      print('$word does not match');
    }
  }
}

In the example, we have five words in a list. We check which words match the .even regular expression.

final rx = RegExp(r'.even');

We define a regular expression with RegExp. The dot (.) metacharacter stands for any single character in the text. Therefore, "even" does not match, because there is no character before "e".

for (final word in words) {
  if (rx.hasMatch(word)) {
    print('$word does match');
  } else {
    print('$word does not match');
  }
}

We go over the elements of the list and check if the elements match the regular expression with hasMatch. Note that hasMatch looks for the pattern anywhere in the string; "Maven" is not matched because its letters are "aven".

$ dart main.dart
Seven does match
even does not match
Maven does not match
Amen does not match
eleven does match

Dart regex alternation

The alternation operator | creates a regular expression with several choices.

main.dart
void main() {
  final words = ['Jane', 'Thomas', 'Robert', 'Lucy', 'Beky', 'John', 'Peter', 'Andy'];
  final rx = RegExp('Jane|Beky|Robert');

  for (final word in words) {
    if (rx.hasMatch(word)) {
      print('the $word matches');
    }
  }
}

We have eight names in the list.

final rx = RegExp('Jane|Beky|Robert');

This regular expression looks for "Jane", "Beky", or "Robert" strings.

$ dart main.dart
the Jane matches
the Robert matches
the Beky matches

Dart regex subpatterns

Subpatterns are patterns within patterns. Subpatterns are created with () characters.

main.dart
void main() {
  final words = [
    'book',
    'bookshelf',
    'bookworm',
    'bookcase',
    'bookish',
    'bookkeeper',
    'booklet',
    'bookmark'
  ];

  final rx = RegExp(r'^book(worm|mark|keeper)?$');

  for (final word in words) {
    if (rx.hasMatch(word)) {
      print('$word does match');
    } else {
      print('$word does not match');
    }
  }
}

We find all words that match the subpattern.

final rx = RegExp(r'^book(worm|mark|keeper)?$');

The regular expression uses a subpattern. The anchors ^ and $ bind the pattern to the whole string. The pattern matches bookworm, bookmark, bookkeeper, and book.

$ dart main.dart
book does match
bookshelf does not match
bookworm does match
bookcase does not match
bookish does not match
bookkeeper does match
booklet does not match
bookmark does match

Dart RegExp firstMatch

The firstMatch function returns the first match as a RegExpMatch, or null if there is none. The stringMatch function returns just the matched text.

main.dart
void main() {
  const text = 'The Sun was shining; I went for a walk.';
  final rx = RegExp(r'\w+ing');

  final match = rx.firstMatch(text);

  if (match != null) {
    print(match.group(0));
    print('${match.start}:${match.end}');
  }

  print(rx.stringMatch('nothing here'));
  print(rx.stringMatch('no match'));
}

The pattern finds a word ending in "ing". The match provides the matched text with group(0) and its position with start and end. Because the result is nullable, we must check it before use.

$ dart main.dart
shining
12:19
nothing
null

Dart RegExp allMatches

The allMatches function finds all matches of the given regular expression. It returns a lazy iterable of RegExpMatch objects.

main.dart
void main() {
  const text = 'The Sun was shining; I went for a walk.';
  final rx = RegExp(r'\w+');
  final found = rx.allMatches(text);

  print('There are ${found.length} words');

  for (final match in found) {
    print('${match.group(0)} ${match.start}:${match.end}');
  }
}

In the example, we find all words in the text.

final rx = RegExp(r'\w+');

The regular expression matches all words; a word is defined here as one or more word characters (letters, digits, and the underscore).

print('There are ${found.length} words');

We print the number of words.

for (final match in found) {
  print('${match.group(0)} ${match.start}:${match.end}');
}

We iterate over all found matches and print them and their indexes.

$ dart main.dart
There are 9 words
The 0:3
Sun 4:7
was 8:11
shining 12:19
I 21:22
went 23:27
for 28:31
a 32:33
walk 34:38

Dart regex capturing groups

Round brackets are used to create capturing groups. This allows us to apply a quantifier to the entire group or to restrict alternation to a part of the regular expression.

main.dart
void main() {
  final sites = ['example.com', 'zetcode.com', 'freebsd.org', 'netbsd.org'];
  final rx = RegExp(r'(\w+)\.(\w+)');

  for (final site in sites) {
    for (final match in rx.allMatches(site)) {
      print(match.group(0));
      print(match.group(1));
      print(match.group(2));
    }

    print('----------------------');
  }
}

In the example, we divide the domain names into two parts by using groups.

final rx = RegExp(r'(\w+)\.(\w+)');

We define two groups with parentheses. The dot character is escaped because it is used in the literal meaning.

for (final match in rx.allMatches(site)) {

We find all matches with allMatches.

print(match.group(0));
print(match.group(1));
print(match.group(2));

The groups are accessed via the group function. The whole match is available with match.group(0); groupCount gives the number of groups.

$ dart main.dart
example.com
example
com
----------------------
zetcode.com
zetcode
com
----------------------
freebsd.org
freebsd
org
----------------------
netbsd.org
netbsd
org
----------------------

Dart regex named groups

A group can be given a name with the (?<name>...) syntax. The named group is then read with namedGroup, which is more readable than a numeric index.

main.dart
void main() {
  final rx = RegExp(r'(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})');
  final match = rx.firstMatch('Released on 2026-10-18.');

  if (match != null) {
    print(match.namedGroup('year'));
    print(match.namedGroup('month'));
    print(match.namedGroup('day'));
    print(match.groupNames.toList());
  }
}

The pattern parses an ISO date. The groupNames property lists the names of the groups.

$ dart main.dart
2026
10
18
[year, month, day]

Dart regex replace

The replaceAll and replaceFirst methods of String accept a regular expression. The replaceAllMapped method computes the replacement from the match.

main.dart
void main() {
  const text = 'The price is 15 dollars and 40 cents.';

  print(text.replaceAll(RegExp(r'\d+'), '#'));
  print(text.replaceFirst(RegExp(r'\d+'), '#'));

  final doubled = text.replaceAllMapped(
    RegExp(r'\d+'),
    (m) => (int.parse(m.group(0)!) * 2).toString(),
  );
  print(doubled);

  print('John Doe'.replaceAllMapped(
    RegExp(r'(\w+) (\w+)'),
    (m) => '${m[2]}, ${m[1]}',
  ));
}

In the last example, the match is indexed directly with m[2], which is a shortcut for m.group(2). The replacement swaps the first and last names.

$ dart main.dart
The price is # dollars and # cents.
The price is # dollars and 40 cents.
The price is 30 dollars and 80 cents.
Doe, John

Dart regex flags

The RegExp constructor has named parameters for the flags: caseSensitive (true by default), multiLine, dotAll, and unicode.

main.dart
void main() {
  final text = 'First line\nsecond line\nthird line';

  final ci = RegExp('FIRST', caseSensitive: false);
  print(ci.hasMatch(text));

  print(RegExp(r'^\w+').allMatches(text).length);
  print(RegExp(r'^\w+', multiLine: true).allMatches(text).length);

  print(RegExp(r'line.second').hasMatch(text));
  print(RegExp(r'line.second', dotAll: true).hasMatch(text));
}

Without multiLine, the anchors ^ and $ match only at the start and end of the whole string. Without dotAll, the dot does not match a newline.

$ dart main.dart
true
1
3
false
true

Dart regex split and escape

A regular expression can also be used to split a string. When the pattern comes from user input, we escape it with RegExp.escape so that special characters are matched literally.

main.dart
void main() {
  const text = 'one, two;three   four';

  print(text.split(RegExp(r'[,;\s]+')));

  const userInput = 'a.b*c';
  final rx = RegExp(RegExp.escape(userInput));

  print(rx.pattern);
  print(rx.hasMatch('xx a.b*c yy'));
  print(rx.hasMatch('xx aXbbc yy'));
}

The text is split at commas, semicolons, and whitespace. The escaped pattern a\.b\*c matches only the literal text a.b*c.

$ dart main.dart
[one, two, three, four]
a\.b\*c
true
false

Source

Dart RegExp - API reference

In this article we covered Dart regular expressions.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Dart tutorials.