Sử dụng Regex để tạo Chuỗi thay vì khớp chúng


108

Tôi đang viết một tiện ích Java giúp tôi tạo ra vô số dữ liệu để kiểm tra hiệu suất. Sẽ thực sự tuyệt vời nếu có thể chỉ định một regex cho các Chuỗi để trình tạo của tôi tạo ra những thứ phù hợp với điều này. Có thứ gì đó ngoài kia đã được nướng sẵn mà tôi có thể sử dụng để làm việc này không? Hay có thư viện nào giúp tôi đi hết quãng đường đó không?

Cảm ơn


1
Đây là một hữu ích thư viện java cung cấp nhiều tính năng cho việc sử dụng regex để tạo String (thế hệ ngẫu nhiên, tạo ra chuỗi dựa trên chỉ số của nó, tạo ra tất cả chuỗi ..) kiểm tra xem nó ra đây
Mifmif

Một sự thay thế khác có thể là cái này
Vladislav Varslavans

Câu trả lời:


40

Chỉnh sửa: Như đã đề cập trong phần nhận xét, có một thư viện có sẵn tại Google Code để đạt được điều này: https://code.google.com/archive/p/xeger/

Xem thêm https://github.com/mifmif/Generex theo gợi ý của Mifmif

Tin nhắn ban đầu:

Thứ nhất, với một regexp đủ phức tạp, tôi tin rằng điều này là không thể. Nhưng bạn sẽ có thể kết hợp một cái gì đó với nhau để tạo ra những regexps đơn giản.

Nếu bạn nhìn vào mã nguồn của lớp java.util.regex.Pattern, bạn sẽ thấy rằng nó sử dụng một đại diện bên trong của các cá thể Node. Mỗi thành phần mẫu khác nhau có một lớp con Node triển khai riêng của chúng. Các nút này được tổ chức thành một cây.

Bằng cách tạo ra một khách truy cập đi qua cây này, bạn sẽ có thể gọi một phương thức trình tạo quá tải hoặc một số loại Trình tạo kết hợp một cái gì đó với nhau.


2
Tôi không chắc Xeger có tốt như vậy không. Nó không thể xử lý các lớp ký tự. Nó không nhận ra một đơn giản [\w]. Nhìn vào dòng cuối cùng của wiki của họ cho chúng ta biết điều đó.
John Red

2
Cũng lưu ý rằng chúng phụ thuộc vào dk.brics.automatonvì vậy hãy chuẩn bị thêm các phụ thuộc pom của bên thứ 3. Hầu hết mọi người không bận tâm về điều đó nhưng tôi ước gì có thứ gì đó nhỏ gọn hơn một chút.
Sridhar Sarnobat,

Có sự thay thế cho xeger và generex. Nó thiếu tất cả những nhược điểm này và không bị lỗi thời. Vui lòng cuộn xuống câu trả lời của tôi.
Vladislav Varslavans

"Thứ nhất, với một regexp đủ phức tạp, tôi tin rằng điều này là không thể." - điều này không hoàn toàn đúng : bất kỳ regex nào đi ngược lại thứ gì đó cũng có thể tạo ra một đầu vào hợp lệ. Giải thích: regexes là loại 3 trên Chomsky Hierarchy, có nghĩa là chúng có thể được biểu thị dưới dạng FSM. Khi bước qua FSM, mỗi cạnh được hiểu là quy tắc cho ký tự tiếp theo, do đó, FSM có thể được sử dụng để phân tích cú pháp hoặc tạo chuỗi. Nếu FSM có một đường dẫn đến thiết bị đầu cuối, một trình tự hợp lệ có thể được xác định. Vì vậy, nó chỉ là "không thể" nếu không có đường dẫn đến thiết bị đầu cuối (đó sẽ là một regex vô dụng).
Lawrence Wagerfield

22

Đã quá muộn để giúp đỡ người đăng ban đầu, nhưng nó có thể giúp một người mới. Generex là một thư viện java hữu ích, cung cấp nhiều tính năng sử dụng regex để tạo chuỗi (tạo ngẫu nhiên, tạo chuỗi dựa trên chỉ mục của nó, tạo tất cả các chuỗi ...).

Thí dụ :

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

Tiết lộ

Dự án được đề cập trên bài đăng này thuộc về người dùng trả lời câu hỏi (Mifmif). Theo các quy tắc , điều này cần được đưa ra.


11
Có vẻ như Generex là dự án của riêng bạn. Bạn có vui lòng đề cập trong bài đăng của mình rằng đây là dự án của riêng bạn, theo các quy tắc ở đây không?
Brian McCutchon

20

Xeger (Java) cũng có thể làm điều đó:

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

1
Xeger hoạt động độc đáo. NHƯNG chắc chắn rằng bạn có jar automaton trên con đường lớp hoặc trong pom của bạn / gradle
DELICIA Brummitt

5

Tôi đã tìm hiểu thư viện gốc của riêng mình cho điều đó (Trong c # nhưng phải dễ hiểu đối với một nhà phát triển Java).

Rxrdg bắt đầu như một giải pháp cho vấn đề tạo dữ liệu thử nghiệm cho một dự án đời thực. Ý tưởng cơ bản là tận dụng các mẫu xác thực (biểu thức chính quy) hiện có để tạo dữ liệu ngẫu nhiên phù hợp với các mẫu đó. Bằng cách này, dữ liệu ngẫu nhiên hợp lệ được tạo ra.

Không khó để viết một trình phân tích cú pháp cho các mẫu regex đơn giản. Sử dụng cây cú pháp trừu tượng để tạo chuỗi thậm chí còn dễ dàng hơn.


liên kết không trỏ đến kho lưu trữ nữa. Tôi sẽ đi với openhub.net/p/rxrdg . Giải pháp không xây dựng, tuy nhiên?
Veverke

4

Trên podcast stackoverflow 11:

Spolsky: Đúng vậy. Ngoài ra còn có một sản phẩm mới, nếu bạn không muốn sử dụng Hệ thống nhóm, bạn bè của chúng tôi tại Redgate có một sản phẩm có tên SQL Data Generator [ http://www.red-gate.com/products/sql_data_generator/index.htm] . Nó là 295 đô la và nó chỉ tạo ra một số dữ liệu thử nghiệm thực tế. Và nó thực hiện những thứ như thực sự tạo ra các thành phố thực trong cột thành phố thực sự tồn tại, và sau đó khi tạo ra những thứ đó, nó sẽ đưa trạng thái đúng, thay vì đưa trạng thái sai hoặc đưa các bang vào các thành phố của Đức và những thứ như ... bạn biết đấy, nó tạo ra dữ liệu trông khá thực tế. Tôi không thực sự chắc chắn tất cả các tính năng là gì.

Đây có lẽ không phải là thứ bạn đang tìm kiếm, nhưng nó có thể là một điểm khởi đầu tốt, thay vì tạo ra của riêng bạn.

Tôi dường như không thể tìm thấy bất cứ điều gì trong google, vì vậy tôi khuyên bạn nên giải quyết vấn đề bằng cách phân tích một biểu thức chính quy nhất định thành các đơn vị công việc nhỏ nhất (\ w, [xx], \ d, v.v.) và viết một số phương pháp cơ bản để hỗ trợ các cụm từ biểu thức chính quy đó.

Vì vậy, đối với \ w bạn sẽ có một phương thức getRandomLetter () trả về bất kỳ ký tự ngẫu nhiên nào và bạn cũng sẽ có getRandomLetter (char startLetter, char endLetter) cung cấp cho bạn một ký tự ngẫu nhiên giữa hai giá trị.


4

Câu hỏi này thực sự cũ, mặc dù vấn đề là thực tế đối với tôi. Tôi đã thử xegerGenerex và chúng dường như không đáp ứng được sự hối tiếc của tôi. Chúng thực sự không xử lý được một số mẫu regex (như a{60000}) hoặc đối với những mẫu khác (ví dụ (A|B|C|D|E|F)) chúng không tạo ra tất cả các giá trị có thể. Vì tôi không tìm thấy bất kỳ giải pháp thích hợp nào khác - tôi đã tạo thư viện của riêng mình.

https://github.com/curious-odd-man/RgxGen

Ngoài ra còn có tạo tác trên trung tâm maven có sẵn.

Ví dụ sử dụng:

RgxGen rgxGen = new RgxGen(aRegex);                     // Create generator
String s = rgxGen.generate();                           // Generate new random value

3

Tôi biết đã có một câu trả lời được chấp nhận, nhưng tôi đã sử dụng Trình tạo dữ liệu của RedGate (cái được đề cập trong câu trả lời của Craig) và nó thực sự hoạt động tốt cho mọi thứ tôi đã ném vào nó. Nó nhanh chóng và điều đó khiến tôi muốn sử dụng cùng một regex để tạo dữ liệu thực cho những thứ như mã đăng ký mà thứ này xuất ra.

Nó cần một regex như:

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

và nó tạo ra hàng tấn mã duy nhất như:

LLK-32U

Đây có phải là một thuật toán bí mật lớn nào đó mà RedGate đã tìm ra và tất cả chúng ta đều gặp may hay đó là điều mà chúng ta chỉ thực sự có thể làm?


3

Tôi đang trên chuyến bay và chỉ thấy câu hỏi: Tôi đã viết giải pháp dễ nhất nhưng không hiệu quả và không đầy đủ. Tôi hy vọng nó có thể giúp bạn bắt đầu viết trình phân tích cú pháp của riêng mình:

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);
}

Bạn có thể muốn chỉ ra loại chuỗi nào được sử dụng làm đầu vào mẫu. Trước hết, việc xác định những thứ như vậy từ mã nguồn không phải là điều dễ dàng. Thứ hai, nếu có bất kỳ sai sót hoặc bất thường nào trong mã nguồn, không có cách nào để xem liệu chúng có cố ý hay không.
Maarten Bodewes

StringTokenizer là một lớp kế thừa được giữ lại vì lý do tương thích mặc dù việc sử dụng nó không được khuyến khích trong mã mới. Thay vào đó, bất kỳ ai đang tìm kiếm chức năng này nên sử dụng phương pháp phân tách của String hoặc gói java.util.regex.
Rohit

2

Bạn sẽ phải viết trình phân tích cú pháp của riêng mình, giống như tác giả của String :: Random (Perl) đã làm. Trên thực tế, anh ta không sử dụng regexes ở bất kỳ đâu trong mô-đun đó, nó chỉ là thứ mà các nhà mã hóa perl đã quen.

Mặt khác, có thể bạn có thể xem qua nguồn để có được một số gợi ý.


CHỈNH SỬA: Chết tiệt, blair đã đánh bại tôi trong 15 giây.


1

Còn lâu mới hỗ trợ một PCRE regexp đầy đủ, nhưng tôi đã viết phương thức Ruby sau đây để lấy một chuỗi giống regexp và tạo ra một biến thể trên đó. (Đối với CAPTCHA dựa trên ngôn ngữ.)

# 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

1

Câu hỏi này rất cũ, nhưng tôi đã tình cờ gặp nó trong quá trình tìm kiếm của chính mình, vì vậy tôi sẽ đưa vào một vài liên kết cho những người khác có thể đang tìm kiếm chức năng tương tự bằng các ngôn ngữ khác.


0

Nếu bạn muốn tạo chuỗi "quan trọng", bạn có thể muốn xem xét:

EGRET http://elarson.pythonanywhere.com/ tạo chuỗi "ác" bao gồm các biểu thức chính quy của bạn

MUTREX http://cs.unibg.it/mutrex/ tạo chuỗi phát hiện lỗi bằng đột biến regex

Cả hai đều là công cụ học thuật (tôi là một trong những tác giả của công cụ sau này) và hoạt động hợp lý.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.