CodeGym /Java Blog /무작위의 /자바의 정규 표현식
John Squirrels
레벨 41
San Francisco

자바의 정규 표현식

무작위의 그룹에 게시되었습니다
정규 표현식은 경험이 많은 프로그래머라도 종종 나중으로 미루는 주제입니다. 그러나 조만간 대부분의 Java 개발자는 텍스트 정보를 처리해야 합니다. 대부분의 경우 이는 텍스트 검색 및 편집을 의미합니다. 정규식 없이는 효과적이고 간결한 텍스트 처리 코드를 생각할 수 없습니다. 미루지 말고 지금 당장 정규식을 다루겠습니다. 그렇게 어렵지 않습니다. Java의 정규 표현식 - 1

정규식(regex)이란 무엇입니까?

사실 정규 표현식은 텍스트에서 문자열을 찾기 위한 패턴입니다. Java에서 이 패턴의 원래 표현은 항상 문자열, 즉 클래스의 객체입니다 String. 그러나 정규식으로 컴파일할 수 있는 문자열은 아닙니다. 정규식 생성 규칙을 준수하는 문자열만 가능합니다. 구문은 언어 사양에 정의되어 있습니다. 정규식은 정규식 구문에서 특별한 의미를 갖는 문자인 메타문자뿐만 아니라 문자와 숫자를 사용하여 작성됩니다. 예를 들어:

String regex = "java"; // The pattern is "java";
String regex = "\\d{3}"; // The pattern is three digits;

Java에서 정규식 만들기

Java에서 정규식을 작성하려면 두 가지 간단한 단계가 필요합니다.
  1. 정규식 구문을 준수하는 문자열로 작성하십시오.
  2. 문자열을 정규식으로 컴파일합니다.
모든 Java 프로그램에서 개체를 생성하여 정규식 작업을 시작합니다 Pattern. 이렇게 하려면 클래스의 두 가지 정적 메서드 중 하나를 호출해야 합니다 compile. 첫 번째 메서드는 정규식을 포함하는 문자열 리터럴인 하나의 인수를 사용하고 두 번째 메서드는 패턴 일치 설정을 결정하는 추가 인수를 사용합니다.

public static Pattern compile (String literal)
public static Pattern compile (String literal, int flags)
매개변수 의 잠재적 값 목록은 클래스 flags에서 정의되며 Pattern정적 클래스 변수로 사용할 수 있습니다. 예를 들어:

Pattern pattern = Pattern.compile("java", Pattern.CASE_INSENSITIVE); // Pattern-matching will be case insensitive.
기본적으로 Pattern클래스는 정규 표현식의 생성자입니다. 내부적으로 이 compile메서드는 클래스의 전용 생성자를 호출하여 Pattern컴파일된 표현을 만듭니다. 이 객체 생성 메커니즘은 불변 객체를 생성하기 위해 이러한 방식으로 구현됩니다. 정규식이 생성되면 구문이 검사됩니다. 문자열에 오류가 있으면 a가 PatternSyntaxException생성됩니다.

정규 표현식 구문

<([{\^-=$!|]})?*+.>정규 표현식 구문은 문자와 결합될 수 있는 문자 에 의존합니다 . 역할에 따라 여러 그룹으로 나눌 수 있습니다.
1. 줄이나 텍스트의 경계를 맞추기 위한 메타문자
메타문자 설명
^^ 줄의 시작
$ 줄의 끝
\비 단어 경계
\비 비단어 경계
\ㅏ 입력의 시작
\G 이전 경기 종료
\지 입력의 끝
\지 입력의 끝
2. 미리 정의된 문자 클래스를 일치시키기 위한 메타문자
메타문자 설명
\디 숫자
\디 숫자가 아닌
\에스 공백 문자
\에스 공백이 아닌 문자
\w 영숫자 문자 또는 밑줄
\W 문자, 숫자 및 밑줄을 제외한 모든 문자
. 모든 문자
3. 제어 문자 일치를 위한 메타 문자
메타문자 설명
\티 탭 문자
\N 개행 문자
\아르 자형 캐리지 리턴
\에프 줄 바꿈 문자
\u0085 다음 줄 문자
\u2028 줄 구분 기호
\u2029 단락 구분자
4. 문자 클래스의 메타문자
메타문자 설명
[알파벳] 나열된 문자(a, b 또는 c)
[^abc] 나열된 것 이외의 모든 문자(a, b 또는 c 제외)
[a-zA-Z] 병합된 범위(a에서 z까지의 라틴 문자, 대소문자 구분 안 함)
[광고[mp]] 문자의 합집합(a에서 d까지, m에서 p까지)
[az&&[데프]] 문자의 교차점(d, e, f)
[az&&[^bc]] 문자 빼기(a, dz)
5. 문자 수를 나타내는 메타 문자(한정 기호). 한정 기호 앞에는 항상 문자 또는 문자 그룹이 옵니다.
메타문자 설명
? 하나 또는 없음
* 0회 이상
+ 한 번 이상
{N} n번
{N,} n회 이상
{n,m} n회 이상 m회 이하

탐욕스러운 수량자

수량사에 대해 알아야 할 한 가지는 탐욕적, 소유적, 꺼려하는 세 가지 종류가 있다는 것입니다. +한정사 뒤에 " " 문자를 추가하여 수량사를 소유격으로 만듭니다 . " "를 추가하여 주저하게 만듭니다 ?. 예를 들어:

"A.+a" // greedy
"A.++a" // possessive
"A.+?a" // reluctant
이 패턴을 사용하여 다양한 유형의 한정 기호가 작동하는 방식을 이해해 봅시다. 기본적으로 수량자는 탐욕적입니다. 즉, 문자열에서 가장 긴 일치 항목을 찾습니다. 다음 코드를 실행하면:

public static void main(String[] args) {
    String text = "Fred Anna Alexander";
    Pattern pattern = Pattern.compile("A.+a");
    Matcher matcher = pattern.matcher(text);
    while (matcher.find()) {
        System.out.println(text.substring(matcher.start(), matcher.end()));
    }
}
이 출력을 얻습니다.

Anna Alexa
정규식 " A.+a"의 경우 패턴 일치는 다음과 같이 수행됩니다.
  1. 지정된 패턴의 첫 번째 문자는 라틴 문자입니다 A. Matcher인덱스 0부터 시작하여 텍스트의 각 문자와 비교합니다. 문자는 F텍스트에서 인덱스 0에 있으므로 Matcher패턴과 일치할 때까지 문자를 반복합니다. 이 예에서 이 문자는 인덱스 5에서 찾을 수 있습니다.

    Java의 정규 표현식 - 2
  2. 패턴의 첫 번째 문자와 일치하는 항목이 발견되면 Matcher두 번째 문자와 일치하는 항목을 찾습니다. .우리의 경우에는 모든 문자를 나타내는 " " 문자입니다 .

    Java의 정규 표현식 - 3

    캐릭터는 n여섯 번째 위치에 있습니다. 확실히 "모든 문자"와 일치하는 자격이 있습니다.

  3. Matcher패턴의 다음 문자를 확인합니다. 우리의 패턴에서는 선행 문자 " "에 적용되는 한정사에 포함됩니다 .+. 패턴에서 "모든 문자"의 반복 횟수가 1회 이상이므로 Matcher"모든 문자"와 일치하는 한 문자열에서 다음 문자를 반복적으로 가져와 패턴에 대해 확인합니다. 이 예에서 — 문자열 끝까지(인덱스 7에서 인덱스 18까지).

    Java의 정규 표현식 - 4

    기본적으로 Matcher문자열을 끝까지 먹습니다. 이것이 바로 "탐욕스러운"의 의미입니다.

  4. Matcher는 텍스트 끝에 도달하고 패턴의 " " 부분에 대한 확인을 마친 후 A.+패턴의 나머지 부분에 대한 확인을 시작합니다. a. 앞으로 더 이상 텍스트가 없으므로 검사는 마지막 문자부터 시작하여 "백오프"로 진행됩니다.

    Java의 정규 표현식 - 5
  5. Matcher.+패턴의 " " 부분에서 반복 횟수를 "기억"합니다 . 이 시점에서 반복 횟수를 하나씩 줄이고 일치하는 항목을 찾을 때까지 텍스트에 대해 더 큰 패턴을 확인합니다.

    Java의 정규 표현식 - 6

소유 수량사

소유 수량자는 탐욕스러운 것과 매우 비슷합니다. 차이점은 텍스트가 문자열 끝까지 캡처된 경우 "백오프"하는 동안 패턴 일치가 없다는 것입니다. 즉, 처음 세 단계는 탐욕 수량자와 동일합니다. 전체 문자열을 캡처한 후 매처는 고려 중인 패턴에 나머지 패턴을 추가하고 캡처된 문자열과 비교합니다. 이 예에서 정규식 " A.++a"을 사용하면 기본 메서드가 일치하는 항목을 찾지 않습니다. Java의 정규 표현식 - 7

꺼려하는 수량사

  1. 탐욕적 다양성과 마찬가지로 이러한 수량자의 경우 코드는 패턴의 첫 번째 문자를 기반으로 일치 항목을 찾습니다.

    Java의 정규 표현식 - 8
  2. 그런 다음 패턴의 다음 문자(모든 문자)와 일치하는 항목을 찾습니다.

    Java의 정규 표현식 - 9
  3. 그리디 패턴매칭과 달리 마지못한 패턴매칭에서는 최단 일치를 찾는다. 즉, 패턴의 두 번째 문자(텍스트에서 위치 6에 있는 문자에 해당하는 마침표)와 일치하는 항목을 찾은 후 Matcher텍스트가 패턴의 나머지 부분인 " a" 문자와 일치하는지 확인합니다.

    Java의 정규 표현식 - 10
  4. n텍스트가 패턴과 일치하지 않으므로(즉 , 인덱스 7에 " " 문자 포함 ) Matcher한정 기호가 하나 이상을 나타내므로 "모든 문자"를 하나 더 추가합니다. 그런 다음 패턴을 위치 5에서 8까지의 텍스트와 다시 비교합니다.

    Java의 정규 표현식 - 11
  5. 우리의 경우 일치하는 항목이 있지만 아직 텍스트 끝에 도달하지 않았습니다. 따라서 패턴 일치는 위치 9부터 다시 시작됩니다. 즉, 유사한 알고리즘을 사용하여 패턴의 첫 번째 문자를 찾고 이것은 텍스트가 끝날 때까지 반복됩니다.

    Java의 정규 표현식 - 12
따라서 이 main방법은 " " 패턴을 사용할 때 다음과 같은 결과를 얻습니다 A.+?a. Anna Alexa 우리의 예에서 볼 수 있듯이 다른 유형의 수량어는 동일한 패턴에 대해 다른 결과를 생성합니다. 따라서 이것을 염두에 두고 찾고 있는 것에 따라 올바른 품종을 선택하십시오.

정규 표현식의 이스케이프 문자

Java의 정규식 또는 원래 표현은 문자열 리터럴이기 때문에 문자열 리터럴에 관한 Java 규칙을 고려해야 합니다. 특히 \Java 소스 코드에서 문자열 리터럴의 백슬래시 문자 " "는 컴파일러에게 다음 문자가 특별하고 특별한 방식으로 해석되어야 함을 알리는 제어 문자로 해석됩니다. 예를 들어:

String s = "The root directory is \nWindows"; // Move "Windows" to a new line
String s = "The root directory is \u00A7Windows"; // Insert a paragraph symbol before "Windows"
즉, 정규식을 설명하고 " \" 문자(예: 메타문자를 나타냄)를 사용하는 문자열 리터럴은 백슬래시를 반복하여 Java 바이트코드 컴파일러가 문자열을 잘못 해석하지 않도록 해야 합니다. 예를 들어:

String regex = "\\s"; // Pattern for matching a whitespace character
String regex = "\"Windows\"";  // Pattern for matching "Windows"
"일반" 문자로 사용하려는 특수 문자를 이스케이프하려면 이중 백슬래시를 사용해야 합니다. 예를 들어:

String regex = "How\\?";  // Pattern for matching "How?"

패턴 클래스의 메서드

Pattern클래스에는 정규 표현식으로 작업하기 위한 다른 메서드가 있습니다.
  • String pattern()‒ 객체를 생성하는 데 사용된 정규식의 원래 문자열 표현을 반환합니다 Pattern.

    
    Pattern pattern = Pattern.compile("abc");
    System.out.println(pattern.pattern()); // "abc"
    
  • static boolean matches(String regex, CharSequence input)– 로 전달된 텍스트에 대해 regex로 전달된 정규식을 확인할 수 있습니다 input. 보고:

    true – 텍스트가 패턴과 일치하는 경우;
    false – 그렇지 않은 경우;

    예를 들어:

    
    System.out.println(Pattern.matches("A.+a","Anna")); // true
    System.out.println(Pattern.matches("A.+a","Fred Anna Alexander")); // false
    
  • int flags()‒ 패턴이 생성되었을 때 설정된 패턴의 매개변수 값을 반환하거나 flags매개변수가 설정되지 않은 경우 0을 반환합니다. 예를 들어:

    
    Pattern pattern = Pattern.compile("abc");
    System.out.println(pattern.flags()); // 0
    Pattern pattern = Pattern.compile("abc",Pattern.CASE_INSENSITIVE);
    System.out.println(pattern.flags()); // 2
    
  • String[] split(CharSequence text, int limit)– 전달된 텍스트를 배열로 분할합니다 String. 이 limit매개변수는 텍스트에서 검색된 최대 일치 수를 나타냅니다.

    • if limit > 0- limit-1일치하는 경우;
    • if limit < 0‒ 텍스트의 모든 일치 항목
    • ‒ 텍스트의 모든 일치 항목 인 경우 limit = 0배열 끝에 있는 빈 문자열은 버려집니다.

    예를 들어:

    
    public static void main(String[] args) {
        String text = "Fred Anna Alexa";
        Pattern pattern = Pattern.compile("\\s");
        String[] strings = pattern.split(text,2);
        for (String s : strings) {
            System.out.println(s);
        }
        System.out.println("---------");
        String[] strings1 = pattern.split(text);
        for (String s : strings1) {
            System.out.println(s);
        }
    }
    

    콘솔 출력:

    
    Fred
    Anna Alexa
    ---------
    Fred
    Anna
    Alexa
    

    아래에서는 개체를 만드는 데 사용되는 클래스의 다른 메서드를 살펴보겠습니다 Matcher.

Matcher 클래스의 메서드

패턴 일치를 수행하기 위해 클래스 의 인스턴스가 Matcher생성됩니다. Matcher정규 표현식의 "검색 엔진"입니다. 검색을 수행하려면 패턴과 시작 인덱스라는 두 가지 항목을 제공해야 합니다. Matcher개체를 만들기 위해 Pattern클래스는 다음 메서드를 제공합니다. рublic Matcher matcher(CharSequence input) 이 메서드는 검색할 문자 시퀀스를 사용합니다. 인터페이스 를 구현하는 클래스의 인스턴스입니다 CharSequence. Stringa 뿐만 아니라 StringBuffer, StringBuilder, Segment또는 를 전달할 수도 있습니다 CharBuffer. 패턴은 메소드가 호출 Pattern되는 객체 입니다 matcher. 매처 생성의 예:

Pattern p = Pattern.compile("a*b"); // Create a compiled representation of the regular expression
Matcher m = p.matcher("aaaaab"); // Create a "search engine" to search the text "aaaaab" for the pattern "a*b"
이제 "검색 엔진"을 사용하여 일치 항목을 검색하고, 텍스트에서 일치 항목의 위치를 ​​가져오고, 클래스의 메서드를 사용하여 텍스트를 바꿀 수 있습니다. 메서드는 boolean find()텍스트에서 다음 일치 항목을 찾습니다. 이 메서드와 루프 문을 사용하여 전체 텍스트를 이벤트 모델의 일부로 분석할 수 있습니다. 즉, 이벤트가 발생할 때, 즉 텍스트에서 일치하는 항목을 찾을 때 필요한 작업을 수행할 수 있습니다. 예를 들어 이 클래스 int start()int end()메서드를 사용하여 텍스트에서 일치하는 위치를 결정할 수 있습니다. String replaceFirst(String replacement)그리고 및 String replaceAll(String replacement)메서드를 사용하여 일치 항목을 대체 매개변수의 값으로 바꿀 수 있습니다 . 예를 들어:

public static void main(String[] args) {
    String text = "Fred Anna Alexa";
    Pattern pattern = Pattern.compile("A.+?a");

    Matcher matcher = pattern.matcher(text);
    while (matcher.find()) {
        int start=matcher.start();
        int end=matcher.end();
        System.out.println("Match found: " + text.substring(start, end) + " from index "+ start + " through " + (end-1));
    }
    System.out.println(matcher.replaceFirst("Ira"));
    System.out.println(matcher.replaceAll("Mary"));
    System.out.println(text);
}
산출:

Match found: Anna from index 5 through 8
Match found: Alexa from index 10 through 14
Fred Ira Alexa
Fred Mary Mary
Fred Anna Alexa
replaceFirst이 예제는 및 replaceAll메소드가 새 String객체(원본 텍스트의 패턴 일치가 인수로 메소드에 전달된 텍스트로 대체되는 문자열)를 생성 함을 분명히 합니다 . 또한 이 replaceFirst메서드는 첫 번째 일치 항목만 바꾸지만 replaceAll텍스트의 모든 일치 항목을 바꿉니다. 원본 텍스트는 변경되지 않습니다. 및 클래스의 가장 빈번한 정규식 연산은 클래스 PatternMatcher바로 내장되어 있습니다 String. split, matches, replaceFirst, 와 같은 방법입니다 replaceAll. 그러나 후드 아래에서 이러한 메서드는 PatternMatcher클래스를 사용합니다. 따라서 추가 코드를 작성하지 않고 프로그램에서 텍스트를 바꾸거나 문자열을 비교하려면 다음 메서드를 사용하십시오.String수업. 고급 기능이 필요한 경우 PatternMatcher클래스를 기억하십시오.

결론

Java 프로그램에서 정규식은 특정 패턴 일치 규칙을 따르는 문자열로 정의됩니다. 코드를 실행할 때 Java 시스템은 이 문자열을 객체로 컴파일하고 객체를 Pattern사용하여 Matcher텍스트에서 일치하는 항목을 찾습니다. 처음에 말했듯이 사람들은 종종 정규 표현식이 어려운 주제라고 생각하여 나중으로 미루곤 합니다. 그러나 기본 구문, 메타 문자 및 문자 이스케이프를 이해하고 정규 표현식의 예를 연구하면 언뜻 보기보다 훨씬 간단하다는 것을 알게 될 것입니다.

더 읽어보기:

코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION