java شرح - regex ننظر وراء دون الحد الأقصى لطول واضح في جاوة




regular expression (3)

إنه خطأ: http://bugs.sun.com/view_bug.do?bug_id=6695369

Pattern.compile() المفترض دائمًا أن يقوم Pattern.compile() بطرح استثناء إذا لم يتمكن من تحديد الطول الأقصى المطابق لمطابقة lookbehind.

لطالما اعتقدت أنه يجب أن يكون طول النظرة الواضحة لتأكيد النظرة في جافا سكريبت API (والعديد من اللغات الأخرى). لذلك ، لا يُسمح بمكبرات النجوم STAR و PLUS داخل خلف النظر .

يبدو أن الموارد العادية عبر الإنترنت العادية-expressions.info تؤكد (بعض) افتراضاتي:

"[...] جافا تأخذ الأشياء خطوة أبعد من خلال السماح بالتكرار المتناهي. لا يزال لا يمكنك استخدام النجمة أو زائد ، ولكن يمكنك استخدام علامة الاستفهام والأقواس المتعرجة مع المعلمة القصوى المحددة. تعترف جافا بحقيقة التكرار المحدود يمكن إعادة كتابتها كبديل من السلاسل ذات أطوال مختلفة ولكنها ثابتة. لسوء الحظ ، تحتوي JDK 1.4 و 1.5 على بعض الخلل عندما تستخدم التباين داخل lookbehind. تم إصلاح هذه في JDK 1.6. [...] "

- http://www.regular-expressions.info/lookaround.html

يعمل استخدام الأقواس المتعرجة ما دام إجمالي طول نطاق الأحرف داخل المظهر الخلفي أصغر أو مساوٍ لـ Integer.MAX_VALUE. لذا فإن هذه المعادات المنطقية صحيحة:

"(?<=a{0,"   +(Integer.MAX_VALUE)   + "})B"
"(?<=Ca{0,"  +(Integer.MAX_VALUE-1) + "})B"
"(?<=CCa{0," +(Integer.MAX_VALUE-2) + "})B"

لكن هذه ليست:

"(?<=Ca{0,"  +(Integer.MAX_VALUE)   +"})B"
"(?<=CCa{0," +(Integer.MAX_VALUE-1) +"})B"

ومع ذلك ، لا أفهم ما يلي:

عندما أقوم بإجراء اختبار باستخدام المدقق * و + داخل نظرة خلفية ، كل شيء يسير على ما يرام (انظر اختبار 1 الاختبار والاختبار 2 ).

ولكن ، عندما أقوم بإضافة حرف واحد في بداية البحث من الاختبار 1 والإختبار 2 ، فإنه يكسر (انظر الإخراج اختبار 3 ).

جعل الجشع * من اختبار 3 متردد ليس له أي تأثير ، فإنه لا يزال يكسر (انظر اختبار 4 ).

هنا هو حزام الاختبار:

public class Main {

    private static String testFind(String regex, String input) {
        try {
            boolean returned = java.util.regex.Pattern.compile(regex).matcher(input).find();
            return "testFind       : Valid   -> regex = "+regex+", input = "+input+", returned = "+returned;
        } catch(Exception e) {
            return "testFind       : Invalid -> "+regex+", "+e.getMessage();
        }
    }

    private static String testReplaceAll(String regex, String input) {
        try {
            String returned = input.replaceAll(regex, "FOO");
            return "testReplaceAll : Valid   -> regex = "+regex+", input = "+input+", returned = "+returned;
        } catch(Exception e) {
            return "testReplaceAll : Invalid -> "+regex+", "+e.getMessage();
        }
    }

    private static String testSplit(String regex, String input) {
        try {
            String[] returned = input.split(regex);
            return "testSplit      : Valid   -> regex = "+regex+", input = "+input+", returned = "+java.util.Arrays.toString(returned);
        } catch(Exception e) {
            return "testSplit      : Invalid -> "+regex+", "+e.getMessage();
        }
    }

    public static void main(String[] args) {
        String[] regexes = {"(?<=a*)B", "(?<=a+)B", "(?<=Ca*)B", "(?<=Ca*?)B"};
        String input = "CaaaaaaaaaaaaaaaBaaaa";
        int test = 0;
        for(String regex : regexes) {
            test++;
            System.out.println("********************** Test "+test+" **********************");
            System.out.println("    "+testFind(regex, input));
            System.out.println("    "+testReplaceAll(regex, input));
            System.out.println("    "+testSplit(regex, input));
            System.out.println();
        }
    }
}

الإخراج:

********************** Test 1 **********************
    testFind       : Valid   -> regex = (?<=a*)B, input = CaaaaaaaaaaaaaaaBaaaa, returned = true
    testReplaceAll : Valid   -> regex = (?<=a*)B, input = CaaaaaaaaaaaaaaaBaaaa, returned = CaaaaaaaaaaaaaaaFOOaaaa
    testSplit      : Valid   -> regex = (?<=a*)B, input = CaaaaaaaaaaaaaaaBaaaa, returned = [Caaaaaaaaaaaaaaa, aaaa]

********************** Test 2 **********************
    testFind       : Valid   -> regex = (?<=a+)B, input = CaaaaaaaaaaaaaaaBaaaa, returned = true
    testReplaceAll : Valid   -> regex = (?<=a+)B, input = CaaaaaaaaaaaaaaaBaaaa, returned = CaaaaaaaaaaaaaaaFOOaaaa
    testSplit      : Valid   -> regex = (?<=a+)B, input = CaaaaaaaaaaaaaaaBaaaa, returned = [Caaaaaaaaaaaaaaa, aaaa]

********************** Test 3 **********************
    testFind       : Invalid -> (?<=Ca*)B, Look-behind group does not have an obvious maximum length near index 6
(?<=Ca*)B
      ^
    testReplaceAll : Invalid -> (?<=Ca*)B, Look-behind group does not have an obvious maximum length near index 6
(?<=Ca*)B
      ^
    testSplit      : Invalid -> (?<=Ca*)B, Look-behind group does not have an obvious maximum length near index 6
(?<=Ca*)B
      ^

********************** Test 4 **********************
    testFind       : Invalid -> (?<=Ca*?)B, Look-behind group does not have an obvious maximum length near index 7
(?<=Ca*?)B
       ^
    testReplaceAll : Invalid -> (?<=Ca*?)B, Look-behind group does not have an obvious maximum length near index 7
(?<=Ca*?)B
       ^
    testSplit      : Invalid -> (?<=Ca*?)B, Look-behind group does not have an obvious maximum length near index 7
(?<=Ca*?)B
       ^

قد يكون سؤالي واضحًا ، لكنني سأظل أسأله: هل يمكن لأي شخص أن يشرح لي لماذا يخفق الاختبار 1 و 2 ، ولا يختبر الاختبار 3 و 4 ؟ كنت أتوقع أن يفشل الجميع ، وليس نصفهم ليعملوا وأن يفشل نصفهم.

شكر.

PS. أنا أستخدم: نسخة جافا 1.6.0_14


نظرة سريعة على شفرة المصدر لـ Pattern.java تكشف عن أن '*' و '+' يتم تنفيذها كمثال على Curly (وهو الكائن الذي تم إنشاؤه للمشغلين المجعد). وبالتالي،

a*

يتم تنفيذه

a{0,0x7FFFFFFF}

و

a+

يتم تنفيذه

a{1,0x7FFFFFFF}

هذا هو السبب في أنك ترى بالضبط نفس السلوكيات للكريستال والنجوم.


يمكنك استخدام array_walk لتطبيق وظيفة preg_match الخاصة بكل عنصر في الصفيف.

http://us3.php.net/array_walk





java regex