정규식을 사용하여 일치하는 대신 문자열 생성


108

성능 테스트를 위해 많은 양의 데이터를 생성하는 데 도움이되는 Java 유틸리티를 작성 중입니다. 내 생성기가 이것과 일치하는 것을 뱉어 내도록 Strings에 대한 정규식을 지정할 수 있으면 정말 멋질 것 입니다. 이 작업을 수행하는 데 사용할 수있는 이미 구운 것이 있습니까? 아니면 저를 가장 많이 데려다주는 도서관이 있습니까?

감사


1
여기에 유용합니다 자바 라이브러리 문자열 (임의 세대, 모든 문자열을 생성, 그것의 지수에 따라 문자열을 생성 ..) 확인해 생성하기 위해 정규식을 사용하여 많은 기능을 제공합니다 여기에
Mifmif

또 다른 대안은 이것
Vladislav Varslavans

답변:


40

편집 : 의견에서 언급했듯이이를 달성하기 위해 Google 코드에서 사용할 수있는 라이브러리가 있습니다 : https://code.google.com/archive/p/xeger/

Mifmif가 제안한 https://github.com/mifmif/Generex 참조

원본 메시지 :

첫째, 충분히 복잡한 정규 표현식을 사용하면 불가능할 수 있다고 생각합니다. 그러나 간단한 정규 표현식을 위해 무언가를 조합 할 수 있어야합니다.

java.util.regex.Pattern 클래스의 소스 코드를 살펴보면 Node 인스턴스의 내부 표현을 사용하는 것을 알 수 있습니다. 각기 다른 패턴 구성 요소에는 Node 하위 클래스의 자체 구현이 있습니다. 이러한 노드는 트리로 구성됩니다.

이 트리를 가로 지르는 방문자를 생성함으로써 오버로드 된 생성기 메서드 또는 무언가를 하나로 묶는 일종의 빌더를 호출 할 수 있어야합니다.


2
Xeger가 그렇게 좋은지 잘 모르겠습니다. 문자 클래스를 처리 할 수 ​​없습니다. 간단한 [\w]. 위키 의 마지막 줄을 보면 알 수 있습니다.
John Red

2
또한 이것에 의존 dk.brics.automaton하므로 타사 pom 종속성을 추가 할 준비를하십시오. 대부분의 사람들은 그것을 신경 쓰지 않지만 조금 더 컴팩트 한 것이 있었으면합니다.
Sridhar Sarnobat

xeger와 generex에 대한 대안이 있습니다. 이러한 모든 단점이 없으며 구식이 아닙니다. 내 대답으로 스크롤하십시오.
Vladislav Varslavans

"첫째, 충분히 복잡한 정규 표현식을 사용하면 불가능할 수 있다고 생각합니다." -이것은 엄격히 사실아닙니다 . 어떤 것에 대해 전달하는 정규식 도 유효한 입력을 생성 할 수 있습니다. 설명 : 정규식은 Chomsky Hierarchy에서 유형 3이므로 FSM으로 표현할 수 있습니다. FSM을 단계별로 실행할 때 각 에지는 다음 문자에 대한 규칙으로 해석되므로 FSM을 사용하여 시퀀스 를 구문 분석 하거나 생성 할 수 있습니다 . FSM에 터미널에 대한 경로가 있으면 유효한 시퀀스를 결정할 수 있습니다. 따라서 터미널에 대한 경로가없는 경우에만 "불가능"합니다 (쓸모없는 정규식이 될 것입니다).
Lawrence Wagerfield

22

원래 포스터를 돕기에는 너무 늦었지만, 새로 온 사람에게 도움이 될 수 있습니다. Generex정규 표현식 을 사용하여 문자열을 생성하기위한 많은 기능을 제공하는 유용한 자바 라이브러리입니다 (무작위 생성, 색인에 따라 문자열 생성, 모든 문자열 생성 ...).

예 :

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

폭로

이 게시물에 언급 된 프로젝트는 질문에 답변 한 사용자 (Mifmif)의 것입니다. 당으로 규칙 이 필요가 제기된다.


11
Generex가 귀하의 프로젝트 인 것 같습니다. 여기 의 규칙에 따라이 프로젝트가 자신의 프로젝트라고 게시물에 언급 해 주시겠습니까 ?
Brian McCutchon


5

내 압연의 루트 갔어요 자신의 그것을 위해 라이브러리 (C #에서을하지만, 자바 개발자를위한 이해하기 쉬워야한다).

Rxrdg는 실제 프로젝트의 테스트 데이터 생성 문제에 대한 해결책으로 시작되었습니다. 기본 아이디어는 기존 (정규식) 유효성 검사 패턴을 활용하여 이러한 패턴을 따르는 임의의 데이터를 만드는 것입니다. 이 방법으로 유효한 임의 데이터가 생성됩니다.

간단한 정규식 패턴에 대한 파서를 작성하는 것은 그리 어렵지 않습니다. 추상 구문 트리를 사용하여 문자열을 생성하는 것이 훨씬 더 쉽습니다.


링크가 더 이상 저장소를 가리 키지 않습니다. 나는 openhub.net/p/rxrdg 로 갈 것입니다 . 그러나 솔루션은 구축되지 않습니다.
Veverke

4

stackoverflow 팟 캐스트 11 :

Spolsky : 네. 새로운 제품도 있습니다. Team System을 사용하고 싶지 않다면 Redgate의 친구들이 SQL Data Generator [ http://www.red-gate.com/products/sql_data_generator/index.htm] 라는 제품을 가지고 있습니다 . . $ 295이고 실제 테스트 데이터를 생성합니다. 그리고 실제로 존재하는 도시 열에 실제 도시를 생성하는 것과 같은 일을합니다. 그런 다음이를 생성하면 주를 잘못 이해하거나 주를 독일 도시에 넣는 대신에 주를 바로 잡을 수 있습니다. 알다시피, 그것은 매우 사실적인 데이터를 생성합니다. 모든 기능이 무엇인지 잘 모르겠습니다.

이것은 아마도 당신이 찾고있는 것이 아닐 수도 있지만, 당신 자신을 만드는 대신 좋은 출발점이 될 수 있습니다.

Google에서 아무것도 찾을 수없는 것 같으므로 주어진 정규식을 가장 작은 작업 단위 (\ w, [xx], \ d 등)로 구문 분석하고 지원할 몇 가지 기본 방법을 작성하여 문제를 해결하는 것이 좋습니다. 그 정규식 문구.

따라서 \ w의 경우 임의의 문자를 반환하는 getRandomLetter () 메서드가 있고 두 값 사이에 임의의 문자를 제공하는 getRandomLetter (char startLetter, char endLetter)도 있습니다.


4

이 질문은 정말 오래되었지만 문제가 실제로 발생했습니다. 나는 xegerGenerex를 시도했지만 그들은 내 요구 사항을 충족하지 않는 것 같습니다. 실제로 일부 정규식 패턴 (예 :)을 처리 하지 못 a{60000}하거나 다른 경우 (예 :) (A|B|C|D|E|F)가능한 모든 값을 생성하지 않습니다. 다른 적절한 솔루션을 찾지 못했기 때문에 자체 라이브러리를 만들었습니다.

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

Maven Central에도 유물이 있습니다.

사용 예 :

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

3

이미 받아 들여진 답변이 있다는 것을 알고 있지만 RedGate의 데이터 생성기 (Craig의 답변에서 언급 한 것)를 사용하고 있으며 내가 던진 모든 것에 대해 정말 잘 작동합니다. 빠르며 동일한 정규식을 사용하여이 일이 뱉어내는 등록 코드와 같은 항목에 대한 실제 데이터를 생성하고 싶습니다.

다음과 같은 정규식이 필요합니다.

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

다음과 같은 수많은 고유 코드를 생성합니다.

LLK-32U

이것은 RedGate가 알아 낸 큰 비밀 알고리즘이고 우리는 모두 운이 좋지 않습니까, 아니면 우리 인간이 실제로 할 수있는 일입니까?


3

나는 비행 중이며 질문을 보았습니다. 가장 쉽고 비효율적이며 불완전한 솔루션을 작성했습니다. 나만의 파서를 작성하는 데 도움이되기를 바랍니다.

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

패턴 입력으로 사용되는 문자열의 종류를 표시 할 수 있습니다. 우선, 소스 코드에서 그러한 것들을 결정하는 것이 그렇게 쉬운 것은 아닙니다. 둘째, 소스 코드에 실수 나 불명확 한 부분이있을 경우 의도적 인 것인지 아닌지 확인할 방법이 없습니다.
Maarten Bodewes 2012

StringTokenizer는 새 코드에서 사용이 권장되지 않지만 호환성을 위해 유지되는 레거시 클래스입니다. 이 기능을 원하는 사람은 String의 split 메소드 또는 java.util.regex 패키지를 대신 사용하는 것이 좋습니다.
Rohit

2

String :: Random (Perl)의 저자처럼 직접 파서를 작성해야합니다. 사실, 그는 해당 모듈의 어느 곳에서도 정규식을 사용하지 않고 펄 코더가 사용되는 것입니다.

다른 한편으로, 포인터를 얻기 위해 source를 살펴볼 수 있습니다 .


편집 : 젠장, 블레어가 날 펀치까지 15 초로 이겼다.


1

전체 PCRE 정규식을 지원하는 것과는 거리가 멀지 만 정규식과 유사한 문자열을 가져 와서 변형을 생성하기 위해 다음 Ruby 메서드를 작성했습니다. (언어 기반 보안 문자의 경우.)

# 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

이 질문은 매우 오래되었지만 내 검색에서 우연히 발견되었으므로 다른 언어로 동일한 기능을 검색 할 수있는 다른 사용자를 위해 몇 개의 링크를 포함 할 것입니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.