/ / Регулярний вираз для перевірки поля фіксованої довжини з обмеженим простором - регулярний вираз

Regex, щоб перевірити поле виправлення довжини з запакованим простором - regex

Скажімо, у мене є текстовий файл для аналізу, який містить певний вміст фіксованої довжини:

123jackysee        45678887
456charliewong     32145644
<3><------16------><--8---> # Not part of the data.

Перші три символи - це ідентифікатор, потім 16-значне ім'я користувача, потім 8-значний номер телефону.

Я хотів би написати регулярний вираз для відповідності та перевірки введення для кожного рядка, того, який я придумав:

(d{3})([A-Za-z ]{16})(d{8})

Ім'я користувача має містити 8-16 символів. Але ([A-Za-z ]{16}) також відповідає нульовому значенню або пробілу. Я думаю ([A-Za-z]{8,16} {0,8}) але він виявив би більше 16 символів. Будь-які пропозиції?

Відповіді:

7 для відповіді № 1

Ні, ні, ні, ні! :-)

Чому люди наполягають на спробі укласти стільки функціональних можливостей в одне твердження RE або SQL?

Моя пропозиція, зробіть щось на зразок:

  • Переконайтеся, що довжина становить 27.
  • Вийміть три компоненти в окремі рядки (0-2, 3-18, 19-26).
  • Перевірте, чи відповідають перші "d{3}".
  • Перевірте, чи відповідає другий "[A-Za-z]{8,} *".
  • Перевірте, чи відповідає третій "d{8}".

Якщо ви хочете, щоб вся перевірка вмістилася в одному рядку вихідного коду, помістіть її у функцію, isValidLine(), і назвеш це.

Навіть щось подібне зробить фокус:

def isValidLine(s):
if s.len() != 27 return false
return s.match("^d{3}[A-za-z]{8,} *d{8}$"):

Не обманюйте себе, думаючи, що це чистий Pythonкоду, це насправді PaxLang, мій власний власний псевдокод. Сподіваємось, це досить зрозуміло, перший рядок перевіряє, чи довжина дорівнює 27, а другий, що відповідає даному RE.

Середнє поле автоматично містить 16 символівусього завдяки першому рядку та тому, що інші два поля мають фіксовану довжину в RE. RE також гарантує, що це вісім або більше букв, за якими слід правильна кількість пробілів.

Здійснити подібні речі за допомогою одного РЕ було б якось жахливо, як:

^d{3}(([A-za-z]{8} {8})
|([A-za-z]{9} {7})
|([A-za-z]{10} {6})
|([A-za-z]{11} {5})
|([A-za-z]{12}    )
|([A-za-z]{13}   )
|([A-za-z]{14}  )
|([A-za-z]{15} )
|([A-za-z]{16}))
d{8}$

Ви можете зробити це, переконавшись, що він проходить два окремо РЕ:

^d{3}[A-za-z]{8,} *d{8}$
^.{27}$

але, оскільки ця остання - це просто перевірка довжини, вона нічим не відрізняється від isValidLine() вище.


0 для відповіді № 2

Я б використав регулярний вираз, який ви запропонували, з невеликим доповненням:

(d{3})([A-Za-z]{3,16} {0,13})(d{8})

який буде відповідати речам, які мають aім’я користувача, яке не є пробілом, але все одно допускає заповнення пробілів. Єдиним доповненням є те, що тоді вам доведеться перевіряти довжину кожного вводу, щоб перевірити правильну кількість символів.


0 для відповіді № 3

Хм ... Залежно від точної версії регулярного виразу, який ви запускаєте, враховуйте:

(?P<id>d{3})(?=[A-Za-zs]{16}d)(?P<username>[A-Za-z]{8,16})s*(?P<phone>d{8})

Зауважте, на 100% впевнені, що це спрацює, і я використав пробіл, а не фактичний пробіл - я нервуюсь від самого пробілу, але, можливо, ви хочете бути більш обмежувальним.

Подивіться, чи працює це. Я лише проміжний з RegEx, тому я можу помилитися.

Перевірте синтаксис названих груп для вашої версії RegEx a) існує та b) відповідає стандарту, який я використовував вище.

EDIT:

Просто, щоб розширити те, що я намагаюся зробити (вибачте, щоб у вас кровоточили очі, Пакс!) Для тих, хто не має великого досвіду RegEx:

(?P<id>d{3})

Це спробує відповідати названій групі захоплення -"id" - тобто три цифри в довжину. Більшість версій RegEx дозволяють використовувати іменовані групи захоплення для вилучення значень, з якими відповідали. Це дозволяє вам перевіряти та збирати дані в той самий час. Різні версії RegEx мають дещо різні синтаксиси для цього - перевірте http://www.regular-expressions.info/named.html для отримання більш детальної інформації щодо вашого конкретного впровадження.

(?=[A-Za-zs]{16}d)

? = - це оператор пошуку.Це виглядає вперед для наступних шістнадцяти символів, і поверне значення true, якщо всі вони є буквами або пробілами І за ними стоїть цифра. Оператор lookahead має нульову довжину, тому він насправді нічого не повертає. Ваш рядок RegEx продовжує рухатись із точки, з якої почався Lookahead. Перевірте http://www.regular-expressions.info/lookaround.html для більш детальної інформації про пошук.

(?P<username>[A-Za-z]{8,16})s*

Якщо запит проходить, тоді ми продовжуємо рахуватиз четвертого символу в. Ми хочемо знайти від восьми до шістнадцяти символів, за якими слід нуль або більше пробілів. Символ "або більше" насправді безпечний, оскільки ми вже переконались у підсумку, що загалом не може бути більше шістнадцяти символів до наступної цифри.

Нарешті,

(?P<phone>d{8})

Це має перевірити восьмизначний номер телефону.

Я трохи нервовий, що це точно не спрацює - ваша версія RegEx може не підтримувати названий синтаксис групи або синтаксис lookahead, який я раніше використовував.

Я також трохи нервовий, що цей регулярний вираз успішно відповідає порожньому рядку. Різні версії регулярного виразу обробляють порожні рядки по-різному.

Ви також можете розглянути можливість закріплення цього регулярного виразу між ^ і $, щоб переконатись, що ви співпадаєте з усією лінією, а не лише частиною більшої лінії.


0 для відповіді № 4

Припускаючи, що ви маєте на увазі регулярний вираз perl і якщо ви дозволите "_" в імені користувача:

perl -ne "вихід 1, якщо / (d {3}) (w {8,16}) s + (d {8}) / && length == 28"

0 для відповіді № 5

@ OP, не кожна проблема потребує регулярного виразу.Вашу проблему досить просто перевірити. залежно від того, якою мовою ви користуєтесь, вони мали б вбудовані рядкові функції. використовувати їх. наступний мінімальний приклад зроблено в Python.

import sys
for line in open("file"):
line=line.strip()
# check first 3 char for digit
if not line[0:3].isdigit(): sys.exit()
# check length of username.
if len(line[3:18]) <8 or len(line[3:18]) > 16: sys.exit()
# check phone number length and whether they are digits.
if len(line[19:26]) == 8 and not line[19:26].isdigit(): sys.exit()
print line

0 для відповіді № 6

Я також не думаю, що вам слід спробувати зібрати всю функціональність в один регулярний вираз. Ось один із способів зробити це:

#!/usr/bin/perl

use strict;
use warnings;

while ( <DATA> ) {
chomp;
last unless /S/;
my @fields = split;
if (
( my ($id, $name) = $fields[0] =~ /^([0-9]{3})([A-Za-z]{8,16})$/ )
and ( my ($phone) = $fields[1] =~ /^([0-9]{8})$/ )
) {
print "ID=$idnNAME=$namenPHONE=$phonen";
}
else {
warn "Invalid line: $_n";
}
}

__DATA__
123jackysee       45678887
456charliewong    32145644
678sdjkfhsdjhksadkjfhsdjjh 12345678

І ось ще один спосіб:

#!/usr/bin/perl

use strict;
use warnings;

while ( <DATA> ) {
chomp;
last unless /S/;
my ($id, $name, $phone) = unpack "A3A16A8";
if ( is_valid_id($id)
and is_valid_name($name)
and is_valid_phone($phone)
) {
print "ID=$idnNAME=$namenPHONE=$phonen";
}
else {
warn "Invalid line: $_n";
}
}

sub is_valid_id    { ($_[0]) = ($_[0] =~ /^([0-9]{3})$/) }

sub is_valid_name  { ($_[0]) = ($_[0] =~ /^([A-Za-z]{8,16})s*$/) }

sub is_valid_phone { ($_[0]) = ($_[0] =~ /^([0-9]{8})$/) }

__DATA__
123jackysee        45678887
456charliewong     32145644
678sdjkfhsdjhksadkjfhsdjjh 12345678

Узагальнююче:

#!/usr/bin/perl

use strict;
use warnings;

my %validators = (
id    => make_validator( qr/^([0-9]{3})$/ ),
name  => make_validator( qr/^([A-Za-z]{8,16})s*$/ ),
phone => make_validator( qr/^([0-9]{8})$/ ),
);

INPUT:
while ( <DATA> ) {
chomp;
last unless /S/;
my %fields;
@fields{qw(id name phone)} = unpack "A3A16A8";

for my $field ( keys %fields ) {
unless ( $validators{$field}->($fields{$field}) ) {
warn "Invalid line: $_n";
next INPUT;
}
}

print "$_ : $fields{$_}n" for qw(id name phone);
}

sub make_validator {
my ($re) = @_;
return sub { ($_[0]) = ($_[0] =~ $re) };
}

__DATA__
123jackysee        45678887
456charliewong     32145644
678sdjkfhsdjhksadkjfhsdjjh 12345678

0 для відповіді № 7

Ви можете використовувати lookahead: ^(d{3})((?=[a-zA-Z]{8,})([a-zA-Z ]{16}))(d{8})$

Тестування:

123jackysee 45678887Матч 456charliewong 32145644 Матч 789jop 12345678 Немає збігу - ім’я користувача занадто коротке 999abcdefghijabcde12345678 Не збігається - "стовпець" імені користувача має менше 16 символів 999abcdefghijabcdef12345678 Матч 999abcdefghijabcdefg12345678 Не відповідає - стовпець імені користувача більше 16 символів