استخدام Regex لإنشاء سلاسل بدلاً من مطابقتها

StackOverflow https://stackoverflow.com/questions/22115

  •  09-06-2019
  •  | 
  •  

سؤال

أنا أكتب أداة Java المساعدة التي تساعدني في توليد كميات كبيرة من البيانات لاختبار الأداء.سيكون من حقًا من الرائع أن أتمكن من تحديد regex للسلاسل بحيث يقوم المولد الخاص بي بإخراج الأشياء التي تتطابق مع هذا.هل هناك شيء مخبوز بالفعل يمكنني استخدامه للقيام بذلك؟أم أن هناك مكتبة تجعلني أقطع معظم الطريق إلى هناك؟

شكرًا

هل كانت مفيدة؟

المحلول

يحرر:

كما ذكرنا في التعليقات، هناك مكتبة متاحة في Google Code لتحقيق ذلك:http://code.google.com/p/xeger

أنظر أيضا https://github.com/mifmif/Generex كما اقترح ميفميف

رسالة أصلية:

أولاً، مع وجود تعبير عادي معقد بما فيه الكفاية، أعتقد أن هذا قد يكون مستحيلاً.ولكن يجب أن تكون قادرًا على تجميع شيء ما معًا من أجل التعبيرات العادية البسيطة.

إذا ألقيت نظرة على الكود المصدري للفئة java.util.regex.Pattern، فسترى أنه يستخدم تمثيلًا داخليًا لمثيلات Node.كل مكون من مكونات النمط المختلفة له تطبيقه الخاص لفئة العقدة الفرعية.يتم تنظيم هذه العقد في شجرة.

من خلال إنتاج زائر يجتاز هذه الشجرة، يجب أن تكون قادرًا على استدعاء طريقة مولد محملة بشكل زائد أو نوع من المُنشئ الذي يجمع شيئًا ما معًا.

نصائح أخرى

زيجر (جافا) قادر على القيام بذلك أيضًا:

String regex = "[ab]{4,6}c";
Xeger generator = new Xeger(regex);
String result = generator.generate();
assert result.matches(regex);

لقد فات الأوان لمساعدة الملصق الأصلي، لكنه قد يساعد الوافد الجديد. جينيريكس هي مكتبة جافا مفيدة توفر العديد من الميزات لاستخدام التعابير المنطقية لإنشاء سلاسل (إنشاء عشوائي، إنشاء سلسلة بناءً على فهرسها، إنشاء جميع السلاسل ...).

مثال :

Generex generex = new Generex("[0-3]([a-c]|[e-g]{1,2})");

// generate the second String in lexicographical order that matches the given Regex.
String secondString = generex.getMatchedString(2);
System.out.println(secondString);// it print '0b'

// Generate all String that matches the given Regex.
List<String> matchedStrs = generex.getAllMatchedStrings();

// Using Generex iterator
Iterator iterator = generex.iterator();
while (iterator.hasNext()) {
    System.out.print(iterator.next() + " ");
}
// it prints 0a 0b 0c 0e 0ee 0e 0e 0f 0fe 0f 0f 0g 0ge 0g 0g 1a 1b 1c 1e
// 1ee 1e 1e 1f 1fe 1f 1f 1g 1ge 1g 1g 2a 2b 2c 2e 2ee 2e 2e 2f 2fe 2f 2f 2g
// 2ge 2g 2g 3a 3b 3c 3e 3ee 3e 3e 3f 3fe 3f 3f 3g 3ge 3g 3g 1ee

// Generate random String
String randomStr = generex.random();
System.out.println(randomStr);// a random value from the previous String list

لقد ذهبت إلى جذر المتداول الخاص بي ملك مكتبة لذلك (في c# ولكن يجب أن تكون سهلة الفهم لمطور Java).

بدأت Rxrdg كحل لمشكلة إنشاء بيانات اختبار لمشروع واقعي.الفكرة الأساسية هي الاستفادة من أنماط التحقق (التعبير العادي) الحالية لإنشاء بيانات عشوائية تتوافق مع هذه الأنماط.بهذه الطريقة يتم إنشاء بيانات عشوائية صالحة.

ليس من الصعب كتابة محلل لأنماط التعبير العادي البسيطة.يجب أن يكون استخدام شجرة بناء جملة مجردة لإنشاء سلاسل أسهل.

في بودكاست Stackoverflow 11:

سبولسكي:نعم.هناك منتج جديد أيضًا، إذا كنت لا ترغب في استخدام نظام الفريق، فلدينا أصدقاؤنا في Redgate منتج يسمى SQL Data Generator [http://www.red-gate.com/products/sql_data_generator/index.htm].تبلغ تكلفته 295 دولارًا أمريكيًا، ويقوم فقط بإنشاء بعض بيانات الاختبار الواقعية.وهي تفعل أشياء مثل إنشاء مدن حقيقية في عمود المدينة الموجودة بالفعل، وبعد ذلك عندما تولد تلك المدن، فإنها ستصحح الدولة، بدلاً من فهم الدولة بشكل خاطئ، أو وضع الولايات في مدن ألمانية وأشياء مثل...كما تعلمون، فهو يولد بيانات ذات مظهر واقعي جدًا.لست متأكدًا حقًا من كل الميزات.

ربما لا يكون هذا ما تبحث عنه، ولكنه قد يكون نقطة انطلاق جيدة، بدلاً من إنشاء نقطة انطلاق خاصة بك.

يبدو أنني لم أجد أي شيء في جوجل، لذا أقترح معالجة المشكلة عن طريق تحليل تعبير عادي معين إلى أصغر وحدات العمل (\w، [x-x]، \d، إلخ) وكتابة بعض الأساليب الأساسية لدعم تلك عبارات التعبير العادي.

لذا، بالنسبة إلى ‎\w، سيكون لديك طريقة getRandomLetter()‎ التي تُرجع أي حرف عشوائي، وسيكون لديك أيضًا getRandomLetter(char startLetter, char endLetter) الذي يمنحك حرفًا عشوائيًا بين القيمتين.

أعلم أن هناك إجابة مقبولة بالفعل، لكنني كنت أستخدمها مولد بيانات RedGate (المذكور في إجابة كريج) وهو يعمل بشكل جيد حقًا مع كل ما طرحته عليه.إنه سريع وهذا يجعلني أرغب في استخدام نفس التعبير العادي لإنشاء البيانات الحقيقية لأشياء مثل رموز التسجيل التي يبصقها هذا الشيء.

يستغرق ريكس مثل:

[A-Z0-9]{3,3}-[A-Z0-9]{3,3}

ويولد الكثير من الرموز الفريدة مثل:

LLK-32U

هل هذه خوارزمية سرية كبيرة اكتشفها RedGate ولم يحالفنا الحظ جميعًا أم أنها شيء يمكننا نحن البشر فعله بالفعل؟

أنا على متن الطائرة ورأيت للتو السؤال:لقد كتبت الحل الأسهل ولكنه غير فعال وغير كامل.آمل أن يساعدك ذلك في البدء في كتابة المحلل اللغوي الخاص بك:

public static void main(String[] args) {

    String line = "[A-Z0-9]{16}";
    String[] tokens = line.split(line);
    char[] pattern = new char[100];
    int i = 0;
    int len = tokens.length;
    String sep1 = "[{";
    StringTokenizer st = new StringTokenizer(line, sep1);

    while (st.hasMoreTokens()) {
        String token = st.nextToken();
        System.out.println(token);

        if (token.contains("]")) {
            char[] endStr = null;

            if (!token.endsWith("]")) {
                String[] subTokens = token.split("]");
                token = subTokens[0];

                if (!subTokens[1].equalsIgnoreCase("*")) {
                    endStr = subTokens[1].toCharArray();
                }
            }

            if (token.startsWith("^")) {
                String subStr = token.substring(1, token.length() - 1);
                char[] subChar = subStr.toCharArray();
                Set set = new HashSet<Character>();

                for (int p = 0; p < subChar.length; p++) {
                    set.add(subChar[p]);
                }

                int asci = 1;

                while (true) {
                    char newChar = (char) (subChar[0] + (asci++));

                    if (!set.contains(newChar)) {
                        pattern[i++] = newChar;
                        break;
                    }
                }
                if (endStr != null) {
                    for (int r = 0; r < endStr.length; r++) {
                        pattern[i++] = endStr[r];
                    }
                }

            } else {
                pattern[i++] = token.charAt(0);
            }
        } else if (token.contains("}")) {
            char[] endStr = null;

            if (!token.endsWith("}")) {
                String[] subTokens = token.split("}");
                token = subTokens[0];

                if (!subTokens[1].equalsIgnoreCase("*")) {
                    endStr = subTokens[1].toCharArray();
                }
            }

            int length = Integer.parseInt((new StringTokenizer(token, (",}"))).nextToken());
            char element = pattern[i - 1];

            for (int j = 0; j < length - 1; j++) {
                pattern[i++] = element;
            }

            if (endStr != null) {
                for (int r = 0; r < endStr.length; r++) {
                    pattern[i++] = endStr[r];
                }
            }
        } else {
            char[] temp = token.toCharArray();

            for (int q = 0; q < temp.length; q++) {
                pattern[i++] = temp[q];
            }
        }
    }

    String result = "";

    for (int j = 0; j < i; j++) {
        result += pattern[j];
    }

    System.out.print(result);
}

سيتعين عليك كتابة المحلل اللغوي الخاص بك، كما فعل مؤلف String::Random (Perl).في الواقع، فهو لا يستخدم التعابير المنطقية في أي مكان في تلك الوحدة، وهذا هو ما اعتاد عليه مبرمجو بيرل.

ومن ناحية أخرى، ربما يمكنك إلقاء نظرة على المصدر, ، للحصول على بعض المؤشرات.


يحرر:اللعنة، لقد سبقني بلير بـ 15 ثانية.

إنه بعيد كل البعد عن دعم regexp الكامل لـ PCRE، لكنني كتبت طريقة Ruby التالية لأخذ سلسلة تشبه regexp وإنتاج نسخة مختلفة عنها.(بالنسبة لاختبار CAPTCHA المستند إلى اللغة.)

# q = "(How (much|many)|What) is (the (value|result) of)? :num1 :op :num2?"
# values = { :num1=>42, :op=>"plus", :num2=>17 }
# 4.times{ puts q.variation( values ) }
# => What is 42 plus 17?
# => How many is the result of 42 plus 17?
# => What is the result of 42 plus 17?
# => How much is the value of 42 plus 17?
class String
  def variation( values={} )
    out = self.dup
    while out.gsub!( /\(([^())?]+)\)(\?)?/ ){
      ( $2 && ( rand > 0.5 ) ) ? '' : $1.split( '|' ).random
    }; end
    out.gsub!( /:(#{values.keys.join('|')})\b/ ){ values[$1.intern] }
    out.gsub!( /\s{2,}/, ' ' )
    out
  end
end

class Array
  def random
    self[ rand( self.length ) ]
  end
end

هذا السؤال قديم جدًا، لكنني عثرت عليه أثناء بحثي الخاص، لذا سأقوم بتضمين رابطين للآخرين الذين قد يبحثون عن نفس الوظيفة بلغات أخرى.

إذا كنت تريد إنشاء سلاسل "حرجة"، فقد تحتاج إلى مراعاة ما يلي:

البلشون الأبيض http://elarson.pythonanywhere.com/الذي يولد سلاسل "شريرة" تغطي تعبيراتك العادية

ميتريكس http://cs.unibg.it/mutrex/الذي ينشئ سلاسل للكشف عن الأخطاء عن طريق طفرة regex

كلاهما أدوات أكاديمية (وأنا أحد مؤلفي الأخير) ويعملان بشكل جيد إلى حد معقول.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top