3

私のジレンマは次のとおりです。外部ファイルの文字列を相互に排他的な正規表現に一致させようとしています(つまり、文字列は複数の正規表現に一致できません)

特定の文字列を、他のユースケースと交差しないことが保証されている正規表現に一致させることができるアルゴリズムを提案しますか?

プログラムは構文的に有効ですが、現状では重複しています。ファイルには2.5mの行があります。

ファイル内の各行をトークン化してから、各条件のフラグを設定することを検討していました(したがって、「x」に[AZ] +が含まれている場合は大文字のフラグを設定します)

  • 正規表現は、次の存在をチェックする必要があります。
    • 句読点
    • 大文字
    • 小文字
    • 整数

考えられるユースケース:

U = Upper-case letter L = Lower-case letter P = Punctuation N = Number

---- null
U--- [A-Z]+
UL-- [A-Za-z]+
U-N- [A-Z0-9]+
ULN- [A-Za-z0-9]+
ULNP [\\p{Punct}\\sA-Za-z0-9]+
-L-- [a-z]+
-LN- [a-z0-9]+
--N- [0-9]
---P [\\p{Punct}\\s]+
U--P [\\p{Punct}\\sA-Z]+
-L-P [\\p{Punct}\\sa-z]+
--NP [\\p{Punct}\\s0-9]+
UL-P [\\p{Punct}\\sA-Za-z]+
U-NP [\\p{Punct}\\sA-Z0-9]+
ULNP [\\p{Punct}\\sA-Za-z0-9]+

私がこれまでに持っているもの(非効率的で、正規表現が重複している)

public static void main(String[] args) {
File file = new File("/home/tyler/workspace/PasswordAnalyzer/docs/test.txt");

try {
    Scanner scan = new Scanner(file);
    while (scan.hasNextLine()) {
        String s = scan.nextLine();
        /*****************************************
        * Evaluate password Strings using RegExs
        ******************************************/
        if(s.matches("[A-Z0-9]+")){
            //Upper-case & numeric

        } else if(s.matches("[a-z0-9]+")){
            //Lower-case & numeric

        } else if(s.matches("[A-Za-z0-9]+")){
            //Alphanumeric

        } else if(s.matches("[A-Za-z]+")){
            //Upper-case & lower-case

        } else if(s.matches("[0-9]+")){
            //Numeric

        } else if(s.matches("[A-Z]+")){
            //Upper-case

        }  else if(s.matches("[a-z]+")){
            //Lower-case

        } else if(s.matches("[\\p{Punct}\\s]+")){
            //Punctuation

        } else if(s.matches("[\\p{Punct}\\sA-Z]+")){
            //Punctuation & upper-case

        } else if(s.matches("[\\p{Punct}\\sa-z]+")){
            //Punctuation & lower-case

        } else if(s.matches("[\\p{Punct}\\s0-9]+")){
            //Punctuation & numeric

        } else if(s.matches("[\\p{Punct}\\sA-Za-z]+")){
            //Punctuation & alphabetical

        } else if(s.matches("[\\p{Punct}\\sA-Z0-9]+")){  
            //Punctuation & upper-case & numeric

        } else if(s.matches("[\\p{Punct}\\sa-z0-9]+")){
            //Punctuation & lower-case & numeric

        } else if(s.matches("[\\p{Punct}\\sA-Za-z0-9]+")){
            //Punctuation & alphanumeric

        } else {
            System.err.println("ERROR: unhandled RegEx");
        } 
    } //loop
} catch (FileNotFoundException fnfe){
    System.err.println(fnfe.getMessage());
}

}//main()

改訂:4つの可能な条件(大文字、小文字、数値、句読点)のフラグを設定し、対応する変数の名前を動的に生成し、それに応じて増分します。考え?

(main()の下部)

public static void main(String[] args) {
File file = new File("/home/tyler/workspace/PasswordAnalyzer/docs/test.txt");
Analyzer a = new Analyzer(); //used by Java reflections object

try {
    Scanner scan = new Scanner(file);
    while (scan.hasNextLine()) {
        String s = scan.nextLine();
        //Flags
        boolean U_flag = false;
        boolean L_flag = false;
        boolean N_flag = false;
        boolean P_flag = false;

        for(int i=0; i<s.length(); i++){
            String c = s.substring(i, i);
            /*****************************************
             * Set flags (U,L,N,P)
             ****************************************/
            //U_flag (upper-case)
            if(c.matches("[A-Z]+")){
                U_flag = true;
            }
            //L_flag (lower-case)
            if(c.matches("[a-z]+")){
                L_flag = true;
            }
            //N_flag (numeric)
            if(c.matches("[0-9]+")){
                N_flag = true;
            }
            //P_flag (punctuation)
            if(c.matches("[\\p{Punct}\\s]+")){
                P_flag = true;
            }
            /*****************************************
             * Identify corresponding counter variable
             ****************************************/
            String dest = "";

            //U_flag
            if(U_flag){dest.concat("U");
            } else {dest.concat("_");}

            //L_flag
            if(L_flag){dest.concat("L");
            } else {dest.concat("_");}

            //N_flag
            if(N_flag){dest.concat("N");
            } else {dest.concat("_");}

            //P_flag
            if(P_flag){dest.concat("P");}

            //increment variable stored in dest (Java reflections?)

        }//for-loop
    } //while-loop
} catch (FileNotFoundException fnfe){
    System.err.println(fnfe.getMessage());
}

}//main()
4

2 に答える 2

4

現状では、多くの重複があります。例えば、

U--- [A-Z]+
UL-- [A-Za-z]+
U-N- [A-Z0-9]+
ULN- [A-Za-z0-9]+
ULNP [\\p{Punct}\\sA-Za-z0-9]+

最初の正規表現で一致する文字列は、後続の式でも一致します。

私があなたの質問を正しく解釈した場合、あなたは各入力文字列を、含まれるさまざまな文字クラスによって特徴付けようとしています。たとえば、文字列ABCDEは のように記述されますがU---Ab9b8は ですULN-

これを行うには、(疑似コード):

for (String s in allStrings)
{
    int charClass = 0
    for (Char c in s.characters)
    {
        case c
            when upper-case: 
                charClas |= 8
                break;
            when lower-case: 
                charClas |= 4
                break;
            when numeric: 
                charClas |= 2
                break;                
            when punctuation: 
                charClas |= 1
                break;
    }
    // do something with charClass
}

「何かをする」コメントではcharClass、ビット文字列として取得される の値にULNP値が含まれます。Uそれを、LNおよびを含むリテラル文字列に変換するにはP、文字列配列を設定します。

String[] ulnpStrings = { "----","---P","--N-","--NP","-L--", "-L-P",... etc };

の値をcharClassその配列のインデックスとして使用します。出現をカウントするには、配列で同じことを行います

int[] ulnpCounts = new int[16];

各反復で charClass の値に基づいて要素をインクリメントします。

    ...
    // do something with charClass
    unlpCounts[charClass]++
}
for (int i=0; i<unlpStrings.length; i++)
{
    System.out.printf("%s %6d\n",unlpStrings[i],unlpCounts[i]);
}
于 2012-11-17T22:52:09.973 に答える
0

これを試して:

Pattern p = Pattern.compile("^(?:([A-Z]+)|([a-z]+)|([0-9]+)|([\\p{Punct}\\s]+)|.)*$");
Matcher m = p.matcher("");
Scanner sc = new Scanner(new File("test.txt"));
while (sc.hasNextLine())
{
  String line = sc.nextLine();
  StringBuilder sb = new StringBuilder();
  if (m.reset(line).matches())
  {
    sb.append(m.start(1) > -1 ? "U" : "-");
    sb.append(m.start(2) > -1 ? "L" : "-");
    sb.append(m.start(3) > -1 ? "N" : "-");
    sb.append(m.start(4) > -1 ? "P" : "-");
  }
  System.out.printf("%s : %s%n", sb.toString(), line);
}

出力例:

U--- : AAAA
-L-- : aaaa
--N- : 2222
---P : %%%%
UL-- : AAAa
U-N- : AAA2
U--P : AAA%

各タイプのキャラクターには、独自のキャプチャ グループが割り当てられます。メソッドは、そのstart(int)グループの最新のキャプチャが開始された場所を示します。の値は-1、グループが試合に参加しなかったことを意味します。( を使用することもできますm.group(int) != null。)

あなたがそれをどのように処理したいのかわからないので、私は失敗した試合について何もしませんでした. また、最後のブランチのドットは、ASCII 以外の文字、数字など、他のブランチでは一致しなかったものと一致することに注意してください。他の文字セットをサポートしたい場合は\p{Lu}、 、\p{Ll}など。

于 2012-11-18T00:09:38.327 に答える