解析するテキストファイルがあり、固定長のコンテンツが含まれているとします。
123jackysee 45678887
456charliewong 32145644
<3><------16------><--8---> # Not part of the data.
最初の3文字はID、次に16文字のユーザー名、次に8桁の電話番号です。
私が思いついた各行の入力に一致して検証する正規表現を書きたいと思います。
(d{3})([A-Za-z ]{16})(d{8})
ユーザー名には8〜16文字を含める必要があります。だが ([A-Za-z ]{16})
null値またはスペースにも一致します。私は ([A-Za-z]{8,16} {0,8})
ただし、16文字を超える文字を検出します。助言がありますか?
回答:
回答№1の場合は7いや、いや、いや、いや! :-)
なぜ人々は非常に多くの機能を単一のREまたはSQLステートメントに詰め込もうと主張するのですか?
私の提案は、次のようなことをします。
- 長さが27であることを確認してください。
- 3つのコンポーネントを別々の文字列(0-2、3-18、19-26)に抽出します。
- 最初の一致を確認します
"d{3}"
. - 2番目が一致することを確認します
"[A-Za-z]{8,} *"
. - 3番目が一致することを確認します
"d{8}"
.
チェック全体をソースコードの1行に収めたい場合は、それを関数に入れます。 isValidLine()
、それを呼び出す。
このようなものでもうまくいくでしょう:
def isValidLine(s):
if s.len() != 27 return false
return s.match("^d{3}[A-za-z]{8,} *d{8}$"):
クリーンなPythonだと思って騙されないでくださいコード、それは実際には私自身の独自の擬似コードであるPaxLangです。うまくいけば、最初の行は長さが27であることを確認し、2番目の行は指定されたREと一致します。
中央のフィールドは自動的に16文字になります最初の行と、他の2つのフィールドがREで固定長であるため、合計。 REは、8つ以上のアルファの後に、適切な数のスペースが続くことも保証します。
単一の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}$
あなたはそれが2つを通過することを確認することによってそれを行うことができます 別々の RE:
^d{3}[A-za-z]{8,} *d{8}$
^.{27}$
しかし、その最後のものは単に長さのチェックであるため、それは isValidLine()
上記。
回答№2の場合は0
私はあなたが提案した正規表現を少し追加して使用します:
(d{3})([A-Za-z]{3,16} {0,13})(d{8})
これは、空白以外のユーザー名ですが、スペースの埋め込みは許可されます。唯一の追加は、正しい文字数を確認するために各入力の長さをチェックする必要があるということです。
回答№3の場合は0
うーん...実行している正規表現の正確なバージョンに応じて、次のことを考慮してください。
(?P<id>d{3})(?=[A-Za-zs]{16}d)(?P<username>[A-Za-z]{8,16})s*(?P<phone>d{8})
これが機能することを100%確信していることに注意してください。実際のスペースの代わりに、空白のエスケープ文字を使用しました。スペース文字だけに神経質になりますが、もっと制限したい場合があります。
それが機能するかどうかを確認します。私は自分自身が正規表現の中間にいるだけなので、エラーが発生している可能性があります。
お使いのバージョンの正規表現の名前付きグループの構文を確認してください。a)存在し、b)上記で使用した標準と一致します。
編集:
正規表現の経験があまりない人のために、私がやろうとしていることを拡張するだけです(目を出血させて申し訳ありません、パックス!)。
(?P<id>d{3})
これは、名前付きキャプチャグループとの照合を試みます-「id」-長さは3桁です。正規表現のほとんどのバージョンでは、名前付きキャプチャグループを使用して、照合した値を抽出できます。これにより、検証とデータキャプチャを行うことができます 同時に。正規表現のバージョンが異なれば、このための構文もわずかに異なります-チェックアウト http://www.regular-expressions.info/named.html 特定の実装に関する詳細については。
(?=[A-Za-zs]{16}d)
?=は先読み演算子です。これは次の16文字を先読みし、それらがすべて文字または空白文字であり、その後に数字が続く場合にtrueを返します。先読み演算子は長さがゼロであるため、実際には何も返されません。RegEx文字列は、先読みが開始された時点から継続します。チェックアウト http://www.regular-expressions.info/lookaround.html 先読みの詳細については。
(?P<username>[A-Za-z]{8,16})s*
先読みが通過した場合、カウントを続けますの4番目の文字から。8〜16文字を検索し、その後に0個以上の空白を追加します。 「またはそれ以上」は実際には安全です。これは、次の桁の前に合計16文字を超えてはならないことを先読みですでに確認しているためです。
最後に、
(?P<phone>d{8})
これにより、8桁の電話番号が確認されます。
これが正確に機能しないことに少し神経質になっています。ご使用のバージョンのRegExは、以前の名前付きグループ構文または先読み構文をサポートしていない可能性があります。
また、この正規表現が空の文字列と正常に一致することにも少し神経質になっています。正規表現のバージョンが異なれば、空の文字列の処理も異なります。
また、この正規表現を^と$の間に固定して、大きな行の一部だけでなく、行全体と一致するようにすることも検討してください。
回答№4の場合は0
あなたがperl正規表現を意味し、ユーザー名に「_」を許可した場合:
perl -ne "/(d {3})(w {8,16})s +(d {8})/ && length == 28でない限り、1を終了します"
回答№5の場合は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
答え№6の場合は0
また、すべての機能を1つの正規表現にまとめようとするべきではないと思います。これを行う1つの方法は次のとおりです。
#!/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
回答№7は0
先読みを使用できます。 ^(d{3})((?=[a-zA-Z]{8,})([a-zA-Z ]{16}))(d{8})$
テスト:
123jackysee 45678887一致 456charliewong32145644マッチ 789jop12345678一致しません-ユーザー名が短すぎます 999abcdefghijabcde12345678一致しません-ユーザー名「列」が16文字未満です 999abcdefghijabcdef12345678一致 999abcdefghijabcdefg12345678一致なし-16文字を超えるユーザー名列