Los espacios en blanco de Dart RegExp no se reconocen

Aug 19 2020

Estoy tratando de implementar un patrón de expresiones regulares para el nombre de usuario que permite letras en inglés, letras árabes, dígitos, guiones y espacios.

El siguiente patrón siempre no devuelve ninguna coincidencia si la cadena de entrada tiene un espacio aunque \ s está incluido en el patrón

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

También intenté reemplazar \ s con "" y \\ s, pero la expresión regular siempre no devuelve coincidencias para ninguna entrada que tenga un espacio.

Editar: Resulta que flutter agrega un carácter Unicode para "Marca de derecha a izquierda" o "Marca de izquierda a derecha" cuando se usa un campo de texto con una combinación de idiomas que van LTR o RTL. Esta marca adicional es un carácter Unicode que se agrega al texto. La expresión regular anterior fallaba debido a este carácter adicional. Para resolver el problema, simplemente haga un replaceAll para estos caracteres. Leer más aquí:https://github.com/flutter/flutter/issues/56514.

Respuestas

2 wp78de Aug 20 2020 at 03:34

Este es un problema bastante desagradable y vale la pena documentarlo en una respuesta aquí.

Como se documenta en la fuente :

  /// 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.

Si bien esto está bien intencionado, puede causar problemas cuando trabaja con patrones de texto LTR / RTL mixtos (como es el caso aquí) y tiene que garantizar la longitud exacta del campo, etc.

La solución sugerida es eliminar todas las marcas de izquierda a derecha :

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}');
}

Relacionado: de derecha a izquierda (RTL) en aleteo