batbat13
batbat13

Reputation: 769

Dart RegExp white spaces is not recognized

I'm trying to implement a regex pattern for username that allows English letters, Arabic letters, digits, dash and space.

The following pattern always returns no match if the input string has a space even though \s is included in the pattern

Pattern _usernamePattern = r'^[a-zA-Z0-9\u0621-\u064A\-\s]{3,30}$';

I also tried replacing \s with " " and \\s but the regex always returns no matches for any input that has a space in it.

Edit: It turns out that flutter adds a unicode character for "Right-To-Left Mark" or "Left-To-Right Mark" when using a textfield with a mix of languages that go LTR or RTL. This additional mark is a unicode character that's gets added to the text. The regex above was failing because of this additional character. To resolve the issue simply do a replaceAll for these characters. Read more here: https://github.com/flutter/flutter/issues/56514.

Upvotes: 1

Views: 1786

Answers (1)

wp78de
wp78de

Reputation: 18950

This is a fairly nasty problem and worth documenting in an answer here.

As documented in the source:

  /// When LTR text is entered into an RTL field, or RTL text is entered into an
  /// LTR field, [LRM](https://en.wikipedia.org/wiki/Left-to-right_mark) or
  /// [RLM](https://en.wikipedia.org/wiki/Right-to-left_mark) characters will be
  /// inserted alongside whitespace characters, respectively. This is to
  /// eliminate ambiguous directionality in whitespace and ensure proper caret
  /// placement. These characters will affect the length of the string and may
  /// need to be parsed out when doing things like string comparison with other
  /// text.

While this is well-intended it can cause problems when you work with mixed LTR/RTL text patterns (as it is the case here) and have to ensure exact field length, etc.

The suggested solution is to remove all left-right-marks:

void main() {
  final String lrm = 'aaaa \u{200e}bbbb';
  print('lrm: "$lrm" with length ${lrm.length}');
  
  final String lrmFree = lrm.replaceAll(RegExp(r'\u{200e}', unicode: true), '');
  print('lrmFree: "$lrmFree" with length ${lrmFree.length}');
}

Related: right-to-left (RTL) in flutter

Upvotes: 2

Related Questions