假设我有一个要解析的文本文件,其中包含一些固定长度的内容:
123jackysee 45678887
456charliewong 32145644
<3><------16------><--8---> # Not part of the data.
前三个字符是ID,然后是16个字符的用户名,然后是8位电话号码。
我想编写一个正则表达式来匹配并验证每一行的输入,我想出的那个:
(\d{3})([A-Za-z ]{16})(\d{8})
用户名应包含8-16个字符。但是([A-Za-z ]{16})
也会匹配空值或空格。我想到([A-Za-z]{8,16} {0,8})
但它会检测超过16个字符。有什么建议吗?
答案 0 :(得分:8)
不,不,不,不! : - )
为什么人们会坚持尝试将如此多的功能打包到单个RE或SQL语句中?
我的建议,做类似的事情:
"\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还确保它有八个或更多个alpha,然后是正确的空格数。
用一个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}$
您可以通过确保它传递两个单独的 RE:
来实现^\d{3}[A-za-z]{8,} *\d{8}$
^.{27}$
但是,由于最后一个只是一个长度检查,它与上面的isValidLine()
没有区别。
答案 1 :(得分:0)
假设你的意思是perl正则表达式,如果你在用户名中允许'_':
perl -ne 'exit 1 unless /(\d{3})(\w{8,16})\s+(\d{8})/ && length == 28'
答案 2 :(得分:0)
嗯......根据您正在运行的正则表达式的确切版本,请考虑:
(?P<id>\d{3})(?=[A-Za-z\s]{16}\d)(?P<username>[A-Za-z]{8,16})\s*(?P<phone>\d{8})
注意100%确定这会有效,而且我使用了空格转义字符而不是实际空格 - 我对自己的空间字符感到紧张,但你可能想要更严格。
看看它是否有效。我自己只与RegEx中介,所以我可能会出错。
查看您的RegEx版本的命名组语法a)是否存在,b)是否符合我上面使用的标准。
编辑:
为那些没有很多RegEx经验的人扩展我想要做的事(抱歉让你的眼睛流血,Pax!):
(?P<id>\d{3})
这将尝试匹配命名的捕获组 - 'id' - 长度为三位数。大多数版本的RegEx允许您使用命名捕获组来提取您匹配的值。这使您可以同时进行验证和数据捕获 。不同版本的RegEx具有稍微不同的语法 - 请查看http://www.regular-expressions.info/named.html以获取有关特定实现的更多详细信息。
(?=[A-Za-z\s]{16}\d)
?=是一个先行操作员。这将查看接下来的16个字符,如果它们都是字母或空白字符,则返回true,后面跟一个数字。前瞻操作符的长度为零,因此它实际上不会返回任何内容。您的RegEx字符串从Lookahead开始的位置继续。有关前瞻的更多详细信息,请查看http://www.regular-expressions.info/lookaround.html。
(?P<username>[A-Za-z]{8,16})\s*
如果前瞻通过,那么我们继续计算第四个字符。我们想要找到八到十六个字符,然后是零个或多个空格。 “或更多”实际上是安全的,因为我们已经确定在前瞻中,在下一个数字之前总共不能超过16个字符。
最后,
(?P<phone>\d{8})
这应该检查八位数的电话号码。
我有点紧张,这不会完全奏效 - 您的RegEx版本可能不支持我习惯的命名组语法或前瞻语法。
我也有点紧张,这个正则表达式会成功匹配一个空字符串。不同版本的Regex处理空字符串的方式不同。
您可能还想考虑将此正则表达式锚定在^和$之间,以确保您与整行匹配,而不仅仅是更大行的一部分。
答案 3 :(得分:0)
我会使用你建议的正则表达式添加一小部分:
(\d{3})([A-Za-z]{3,16} {0,13})(\d{8})
将匹配具有非空白用户名但仍允许空格填充的内容。唯一的补充是你必须检查每个输入的长度以验证正确的字符数。
答案 4 :(得分:0)
@ 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
答案 5 :(得分:0)
我也认为您不应该尝试将所有功能打包到单个正则表达式中。这是一种方法:
#!/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=$id\nNAME=$name\nPHONE=$phone\n";
}
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=$id\nNAME=$name\nPHONE=$phone\n";
}
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
答案 6 :(得分:0)
您可以使用前瞻:^(\d{3})((?=[a-zA-Z]{8,})([a-zA-Z ]{16}))(\d{8})$
测试:
123jackysee 45678887 Match 456charliewong 32145644 Match 789jop 12345678 No Match - username too short 999abcdefghijabcde12345678 No Match - username 'column' is less that 16 characters 999abcdefghijabcdef12345678 Match 999abcdefghijabcdefg12345678 No Match - username column more that 16 characters