web-dev-qa-db-ja.com

正規表現に一致するランダムな文字列

特定の正規表現に一致するランダムな英数字の文字列をどのように作成しますか?

これは特に、通常のパスワード要件を満たす初期パスワードを作成するためのものです。

26

ウェルプ、ただ考えているだけですが、正規表現に一致するランダム入力を生成するという一般的な質問は、ランダムの十分にリラックスした定義と正規表現の十分に厳密な定義のために私には実行可能に聞こえます。 ()| *と英字のみを許可する古典的な正式な定義を考えています。

正規表現は、 有限オートマトン と呼ばれる形式マシンにマップできます。このようなマシンは、最終状態と呼ばれる特定のノード、初期状態と呼ばれるノード、および各エッジのアルファベットからの文字を含む有向グラフです。初期状態で開始し、グラフを介して各文字でラベル付けされた1つのエッジをトラバースし、最終状態で終了することが可能な場合、Wordは正規表現によって受け入れられます。

グラフを作成してから、最終状態から開始し、ランダムなエッジを後方にトラバースして、パスを追跡することができます。標準的な構造では、グラフ内のすべてのノードは初期状態から到達可能であるため、回復不能なミスを犯したり、バックトラックしたりすることを心配する必要はありません。初期状態に達したら、停止して、今後のパスを読み取ります。それが正規表現の一致です。

ただし、いつ、または初期状態に到達するかについては、特に保証はありません。生成された文字列が「ランダム」であるという意味と、そもそも言語からランダムな要素を期待しているという意味を理解する必要があります。

たぶん、それが問題について考えるための出発点です!

これを書き留めたので、単純な文字列が残るまで、選択を繰り返し解決して正規表現パターンを単純化する方が簡単なように思われます。パターン内の最初の非アルファベット文字を見つけます。 *の場合は、前の項目を数回複製し、*を削除します。 |の場合は、ORを実行したアイテムのどれを保存するかを選択し、残りを削除します。左のパレンについても同じことを行いますが、一致する右のパレンに続く文字を確認します。これは、正規表現を最初にツリー表現に解析して、パレンのグループ化構造を操作しやすくする場合に、おそらく簡単です。

正規表現が実際に何かに一致するかどうかを判断することは、停止問題と同等であると心配している人にとっては、いいえ、正規言語は非常に適切に動作します。 2つの正規表現が同じ受け入れられた文字列のセットを記述しているかどうかがわかります。基本的に上記のマシンを作成し、次にアルゴリズムに従って、正規の最小の同等のマシンを作成します。 2つの正規表現に対してこれを実行し、結果の最小マシンが同等であるかどうかを確認します。これは簡単です。

19
Ken

String :: Random in Perlは、正規表現のサブセットからランダムな文字列を生成します。

#!/usr/bin/Perl

use strict;
use warnings;

use String::Random qw/random_regex/;

print random_regex('[A-Za-z]{3}[0-9][A-Z]{2}[!@#$%^&*]'), "\n";
17
Chas. Owens

特定の問題がある場合は、おそらく特定の正規表現を念頭に置いています。私はその正規表現を取り、それが何を意味するのかを単純な人間の言葉で理解し、そこから作業します。

一般的な正規表現のランダム一致ジェネレーターを作成するのは可能だと思いますが、特定のケースを処理するだけでなく、はるかに多くの作業が必要になる可能性があります-そのケースが数回変更されたとしても1年。

(実際には、最も一般的な意味でランダムな一致を生成することは不可能かもしれません-「任意の文字列がこの正規表現に一致するか」の問題が変装の停止問題であるという漠然とした記憶があります。非常に削減された正規表現言語ででももっと運がいいかもしれません。)

6
Jon Skeet

私は Parsley と書きました。これは、レクサーとジェネレーターで構成されています。

  • レクサーは、正規表現のような文字列をトークンのシーケンスに変換するためのものです。
  • Generatorは、これらのトークンを使用して、定義された数のコードを生成しています。
$generator = new \Gajus\Parsley\Generator();

/**
 * Generate a set of random codes based on Parsley pattern.
 * Codes are guaranteed to be unique within the set.
 *
 * @param string $pattern Parsley pattern.
 * @param int $amount Number of codes to generate.
 * @param int $safeguard Number of additional codes generated in case there are duplicates that need to be replaced.
 * @return array
 */
$codes = $generator->generateFromPattern('FOO[A-Z]{10}[0-9]{2}', 100);

上記の例では、それぞれに「FOO」というプレフィックスが付いた100個のコードを含む配列が生成され、その後に「ABCDEFGHKMNOPRSTUVWXYZ23456789」干し草スタックから10文字、「0123456789」干し草スタックから2つの数字が続きます。

3
Gajus

このPHPライブラリは有望に見えます: ReverseRegex

これらすべてのように、正規表現のサブセットのみを処理しますが、英国の郵便番号のようなかなり複雑な処理を実行できます。

([A-PR-UWYZ]([0-9]([0-9]|[A-HJKSTUW])?|[A-HK-Y][0-9]([0-9]|[ABEHMNPRVWXY])?) ?[0-9][ABD-HJLNP-UW-Z]{2}|GIR0AA)

出力

D43WF
B6 6SB
MP445FR
P9 7EX
N9 2DH
GQ28 4UL
NH1 2SL
KY2 9LS
TE4Y 0AP
2
Tamlyn

正規表現を解析し、ランダムな長さなどの文字範囲のランダムなメンバーを生成できる文字列ジェネレーターを作成する必要があります。

はるかに簡単なのは、特定のルール(小文字で始まり、句読点、大文字と数字、6文字以上など)を使用してランダムパスワードジェネレーターを作成し、正規表現を作成して、上記のルールは有効です。

1
workmad3

最小の長さと3-of-4 *(または同様の)要件の両方があると仮定すると、まともなパスワードジェネレータを使用する傾向があります。

私は過去にいくつか(Webベースとコマンドラインの両方)を構築しましたが、3-of-4ルールを渡すために生成された複数の文字列をスキップする必要はありませんでした。

  • 3-of-4:小文字、大文字、数字、記号の3つ以上の特性が必要です。
0
warren

それは可能です(たとえば、Haskell regexpモジュールには、特定の正規表現に一致するはずの文字列を自動的に生成するテストスイートがあります)。

ただし、手元にある単純なタスクの場合は、単純なパスワードジェネレータを使用して、その出力を正規表現でフィルタリングする方がよい場合があります。

0
ADEpt