java.util.regex-Pattern.compile ()의 중요성?
Pattern.compile()
방법 의 중요성은 무엇입니까 ?
왜 Matcher
객체 를 얻기 전에 정규식 문자열을 컴파일해야 합니까?
예를 들면 다음과 같습니다.
String regex = "((\\S+)\\s*some\\s*";
Pattern pattern = Pattern.compile(regex); // why do I need to compile
Matcher matcher = pattern.matcher(text);
compile()
방법은 항상 어떤 시점에서라고합니다; Pattern 객체를 만드는 유일한 방법입니다. 그래서 질문은 실제로 왜 명시 적으로 호출해야 합니까? 한 가지 이유는 group(int)
캡처 그룹의 컨텐츠를 검색하는 것과 같은 메소드를 사용할 수 있도록 Matcher 오브젝트에 대한 참조가 필요하기 때문입니다 . Matcher 객체를 잡는 유일한 방법은 Pattern 객체의 matcher()
메서드를 통하는 것 뿐이며 Pattern 객체를 잡는 유일한 방법은 compile()
메서드를 통하는 것 입니다. 그런 다음 find()
달리 matches()
String 또는 Pattern 클래스에서 복제되지 않는 메소드가 있습니다.
다른 이유는 동일한 Pattern 객체를 반복해서 생성하지 않기위한 것입니다. String에서 정규식으로 구동되는 메소드 중 하나 (또는 matches()
Pattern 의 정적 메소드) 를 사용할 때마다 새 Pattern 및 새 Matcher가 작성됩니다. 따라서이 코드 스 니펫 :
for (String s : myStringList) {
if ( s.matches("\\d+") ) {
doSomething();
}
}
... 이것과 정확히 같습니다 :
for (String s : myStringList) {
if ( Pattern.compile("\\d+").matcher(s).matches() ) {
doSomething();
}
}
분명히, 그것은 많은 불필요한 일을하고 있습니다. 실제로 실제 일치를 수행하는 것보다 정규식을 컴파일하고 Pattern 객체를 인스턴스화하는 데 더 오래 걸릴 수 있습니다. 따라서 일반적으로 루프에서 해당 단계를 끌어내는 것이 좋습니다. 거의 비싸지 않지만 미리 Matcher를 만들 수도 있습니다.
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher("");
for (String s : myStringList) {
if ( m.reset(s).matches() ) {
doSomething();
}
}
.NET 정규 표현식에 익숙하다면 Java의 compile()
메소드가 .NET의 RegexOptions.Compiled
수정 자 와 관련 이 있는지 궁금 할 것입니다 . 내 대답은 아니오 야. Java의 Pattern.compile()
메소드는 .NET의 Regex 생성자와 동일합니다. Compiled
옵션 을 지정할 때 :
Regex r = new Regex(@"\d+", RegexOptions.Compiled);
... 정규식을 CIL 바이트 코드로 직접 컴파일하여 훨씬 빠른 속도로 수행 할 수 있지만 선행 처리 및 메모리 사용에 상당한 비용이 소요됩니다. 정규식의 스테로이드로 생각하십시오. Java에는 동등한 것이 없습니다. 씬 뒤에서 생성 된 패턴 String#matches(String)
과으로 명시 적으로 생성 한 패턴 사이에는 차이가 없습니다 Pattern#compile(String)
.
(편집 : 원래는 모든 .NET Regex 객체가 캐시되었다고 말했지만 잘못되었습니다. .NET 2.0부터 자동 캐싱 Regex.Matches()
은 Regex 생성자를 직접 호출 할 때가 아닌. 와 같은 정적 메소드에서만 발생합니다 . ref )
컴파일 은 정규 표현식을 구문 분석 하고 메모리 내 표현을 작성합니다 . 컴파일 오버 헤드는 일치하는 것보다 중요합니다. 패턴을 반복해서 사용하는 경우 컴파일 된 패턴을 캐시하는 성능이 약간 향상됩니다.
Pattern
Java 를 컴파일 할 때 String
더 빨리 일치하는 것을 찾기 위해 약간의 계산을 수행합니다 . (정규식의 메모리 내 표현을 만듭니다)
Pattern
여러 번 재사용하려는 경우 Pattern
매번 새 것을 만드는 것보다 성능이 크게 향상 됩니다.
Pattern을 한 번만 사용하는 경우 컴파일 단계는 추가 코드 줄처럼 보이지만 실제로는 일반적인 경우에 매우 유용 할 수 있습니다.
성능과 메모리 사용량의 문제이며, 많이 사용해야하는 경우 컴파일 된 패턴을 준수하십시오. 정규식의 일반적인 사용의 유효성을 검사 사용자이다 입력 (형식) , 또한 사용자에 대한 출력 데이터 형식을 컴파일 된 패턴을 저장, 이러한 클래스에서, 그들은 일반적으로 많이 불리는으로 매우 논리적 인 것 같다.
아래는 실제로 유효성 검사기 인 샘플 유효성 검사기입니다.
public class AmountValidator {
//Accept 123 - 123,456 - 123,345.34
private static final String AMOUNT_REGEX="\\d{1,3}(,\\d{3})*(\\.\\d{1,4})?|\\.\\d{1,4}";
//Compile and save the pattern
private static final Pattern AMOUNT_PATTERN = Pattern.compile(AMOUNT_REGEX);
public boolean validate(String amount){
if (!AMOUNT_PATTERN.matcher(amount).matches()) {
return false;
}
return true;
}
}
As mentioned by @Alan Moore, if you have reusable regex in your code, (before a loop for example), you must compile and save pattern for reuse.
Pre-compiling the regex increases the speed. Re-using the Matcher gives you another slight speedup. If the method gets called frequently say gets called within a loop, the overall performace will certainly go up.
Similar to 'Pattern.compile' there is 'RECompiler.compile' [from com.sun.org.apache.regexp.internal] where:
1. compiled code for pattern [a-z] has 'az' in it
2. compiled code for pattern [0-9] has '09' in it
3. compiled code for pattern [abc] has 'aabbcc' in it.
Thus compiled code is a great way to generalize multiple cases. Thus instead of having different code handling situation 1,2 and 3 . The problem reduces to comparing with the ascii of present and next element in the compiled code, hence the pairs. Thus
a. anything with ascii between a and z is between a and z
b. anything with ascii between 'a and a is definitely 'a'
Pattern class is the entry point of the regex engine.You can use it through Pattern.matches() and Pattern.comiple(). #Difference between these two. matches()- for quickly check if a text (String) matches a given regular expression comiple()- create the reference of Pattern. So can use multiple times to match the regular expression against multiple texts.
For reference:
public static void main(String[] args) {
//single time uses
String text="The Moon is far away from the Earth";
String pattern = ".*is.*";
boolean matches=Pattern.matches(pattern,text);
System.out.println("Matches::"+matches);
//multiple time uses
Pattern p= Pattern.compile("ab");
Matcher m=p.matcher("abaaaba");
while(m.find()) {
System.out.println(m.start()+ " ");
}
}
Pattern.compile()
allow to reuse a regex multiple times (it is threadsafe). The performance benefit can be quite significant.
I did a quick benchmark:
@Test
public void recompile() {
var before = Instant.now();
for (int i = 0; i < 1_000_000; i++) {
Pattern.compile("ab").matcher("abcde").matches();
}
System.out.println("recompile " + Duration.between(before, Instant.now()));
}
@Test
public void compileOnce() {
var pattern = Pattern.compile("ab");
var before = Instant.now();
for (int i = 0; i < 1_000_000; i++) {
pattern.matcher("abcde").matches();
}
System.out.println("compile once " + Duration.between(before, Instant.now()));
}
compileOnce was between 3x and 4x faster. I guess it highly depends on the regex itself but for a regex that is often used, I go for a static Pattern pattern = Pattern.compile(...)
참고URL : https://stackoverflow.com/questions/1720191/java-util-regex-importance-of-pattern-compile
'development' 카테고리의 다른 글
GCC 기본 포함 디렉토리는 무엇입니까? (0) | 2020.07.26 |
---|---|
회전 된 xticklabel을 해당 xticks와 정렬 (0) | 2020.07.26 |
Django Admin : 데이터베이스 필드가없는 사용자 정의 list_display 필드 중 하나를 기준으로 정렬하는 방법 (0) | 2020.07.26 |
Windows 10에서 환경 변수가 너무 큼 (0) | 2020.07.26 |
C # 응용 프로그램 용 설치 프로그램을 만들고 .NET Framework 설치 관리자를 설치 프로그램에 포함 (0) | 2020.07.26 |