Реактивная действительность формы на основе IP-адресов RegEx - PullRequest
1 голос
/ 13 февраля 2020

Обновление: Я считаю, что это поведение можно воспроизвести с помощью простого регулярного выражения, например /^[0-9]+$/. Это также можно воспроизвести, используя пользовательскую функцию проверки, такую ​​как

export function textareaPattern(pattern: RegExp): ValidatorFn {
    return (control: AbstractControl): {[key: string]: any} | null => {
        const values = control.value.split('\n');
        let mismatch = false;
        values.forEach(val => {
            mismatch = !pattern.test(val);
            if(mismatch) {
                return {textareaPattern: {value: control.value}}
            }
        });
        return null;
    }
}

Исходное сообщение: У меня есть регулярное выражение, предназначенное для проверки того, что пользователь ввел несколько действительных IP-адресов. адреса - по одному на строку - в текстовой области.

/ ^ (? :( ?: 25 [0-5] | 2 [0-4] [0-9] | [01] ? [0-9] [0-9])) {3} (?: 25 [0-5] |?. 2 [0-4] [0-9] |? [01] [0-9] [ 0-9]?) (/ ([0-9] | [1-2] [0-9] | 3 [0-2]))? $ \ N? / Gim

Регулярное выражение работает по счастливому пути, но становится странным, когда присутствуют как действительная, так и недействительная запись.

Если я введу все допустимые значения, элемент управления формы действителен, как и ожидалось. Пример:

10.1.121.2
10.2.121.3
10.3.121.4

Если я введу все недопустимые значения, элемент управления формы будет неверным, как и ожидалось. Пример:

butter
potato
123

Если я введу комбинацию действительных и недействительных значений, элемент управления формы будет чередоваться между действительным и недействительным в зависимости от длины записи. Если длина записи четная, она недействительна, а нечетная действительна. Как странно.

длина: 12, недействительно

10.1.121.1
f

длина: 13, допустимо

10.1.121.1
fo

Я думаю, что проблема заключается в RegEx, но я Я признаю, что мне нелегко расшифровывать такого бегемота RegEx.

RegEx должно соответствовать:

192.168.1.1
255.203.232.1
1.0.12.1

RegEx не должно совпадать:

256.1.12.1
1934.1.22.3
201.foobar.201.1

Минимальный, воспроизводимый пример (дополнено решением) : https://stackblitz.com/edit/angular-v4f35a?file=src%2Fapp%2Fapp.component.ts

1 Ответ

0 голосов
/ 18 февраля 2020

Таким образом, это сводилось к двум проблемам.

Первая проблема состояла в том, что флаг global для RegExes заставляет механизм JS отслеживать свойство lastIndex, с которого начнется следующий поиск, когда myRegex.test() вызывается снова. Поскольку объект регулярного выражения одинаков во всем процессе проверки, этот lastIndex обновляется и на него ссылаются при вводе, а форма повторно проверяется.

Вторая проблема заключается в том, что без global форма будет рассматриваться действует до тех пор, пока одна строка верна. Таким образом, мой ввод может быть

192.168.foobar
192.168.1.1
hello world!

, и форма действительна из-за строки 2.

Мое решение

Я реализовал пользовательский валидатор для текстовых областей. Он принимает мое регулярное выражение (флаг sans g) и разбивает содержимое текстовой области на \n. Он сразу предполагает отсутствие несовпадений, затем для каждой строки проверяет, соответствует ли строка RegEx. Если нет, он не соответствует и возвращает объект, содержащий содержимое текстовой области:

import {AbstractControl, ValidatorFn} from '@angular/forms';

export function multilinePattern(pattern: RegExp): ValidatorFn {
  return (control: AbstractControl): {[key: string]: any} | null => {
    const values = control.value.split('\n');
    if (values.length === 1 && values[0] === '') {
      return null;
    }
    let mismatch = false;
    values.forEach((val: string) => {
      if (!pattern.test(val)) {
        mismatch = true;
      }
    });
    return mismatch ? {multilinePattern: {value: control.value}} : null;
  };
}
...