JavaRush /Java Blog /Random-KO /Java의 정규식(RegEx)

Java의 정규식(RegEx)

Random-KO 그룹에 게시되었습니다
정규식은 프로그래머, 경험이 많은 프로그래머라도 종종 나중으로 미루는 주제입니다. 그러나 대부분의 Java 개발자는 조만간 텍스트 처리를 처리해야 합니다. 대부분의 경우 - 텍스트 및 편집에서 검색 작업을 수행합니다. 정규식이 없으면 텍스트 처리와 관련된 생산적이고 컴팩트한 프로그램 코드는 상상할 수 없습니다. 그러니 미루지 말고 지금 당장 "단골"을 처리합시다. 이것은 그렇게 어려운 작업이 아닙니다.

RegEx 정규식이란 무엇입니까?

실제로 정규식(Java의 RegEx)은 텍스트에서 문자열을 검색하기 위한 패턴입니다. Java에서 이 패턴의 초기 표현은 항상 문자열, 즉 String 클래스의 객체입니다. 그러나 어떤 문자열도 정규식으로 컴파일할 수 없으며, 정규식 작성 규칙(언어 사양에 정의된 구문)을 따르는 문자열만 컴파일할 수 있습니다. 정규식을 작성하려면 정규식 구문에서 특별한 의미를 갖는 문자인 메타문자뿐만 아니라 알파벳과 숫자도 사용됩니다. 예를 들어:
String regex = "java"; // string template "java";
String regex = "\\d{3}"; // string template of three numeric characters;

Java에서 정규 표현식 만들기

Java에서 RegEx를 생성하려면 다음 두 가지 간단한 단계를 따라야 합니다.
  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);//searching for matches with the pattern will be done case-insensitively.
기본적으로 클래스 Pattern는 정규식 생성자입니다. 내부적으로 이 메서드는 compile클래스의 전용 생성자를 호출하여 Pattern컴파일된 뷰를 생성합니다. 템플릿 인스턴스를 생성하는 이 방법은 이를 불변 객체로 생성한다는 목표로 구현됩니다. 생성 시 정규식의 구문 검사가 수행됩니다. 행에 오류가 있으면 예외가 생성됩니다 PatternSyntaxException.

정규식 구문

정규식 구문은 <([{\^-=$!|]})?*+.>알파벳 문자와 결합할 수 있는 기호 사용을 기반으로 합니다. 역할에 따라 여러 그룹으로 나눌 수 있습니다.
1. 줄 경계 또는 텍스트 일치를 위한 메타 문자
메타 문자 목적
^ 줄의 시작
$ 줄 끝
\비 단어 경계
\비 단어 제한이 아닌
\ㅏ 입력 시작
\G 이전 경기 종료
\지 입력 끝
\지 입력 끝
2. 문자 클래스 검색을 위한 메타문자
메타 문자 목적
\디 디지털 기호
\디 숫자가 아닌 문자
\에스 공백 문자
\에스 공백이 아닌 문자
\w 영숫자 또는 밑줄
\W 알파벳, 숫자, 밑줄을 제외한 모든 문자
. 모든 문자
3. 텍스트 편집 기호 검색을 위한 메타문자
메타 문자 목적
\티 탭 문자
\N 개행 문자
\아르 자형 캐리지 리턴 문자
\에프 새 페이지로 이동
\u0085 다음 줄 문자
2028년 줄 구분 문자
2029년 단락 구분 기호
4. 문자 그룹화를 위한 메타문자
메타 문자 목적
[a B C] 위 중 하나(a, b 또는 c)
[^abc] 나열된 것 이외의 것(a, b, c 제외)
[a-zA-Z] 범위 병합(라틴 문자 a~z는 대소문자를 구분하지 않음)
[광고[MP]] 문자 연결(a에서 d, m에서 p)
[az&&[def]] 기호의 교차점(기호 d,e,f)
[az&&[^bc]] 문자 빼기(문자 a, dz)
5. 문자 수를 나타내는 메타 기호 - 수량자. 수량자는 항상 문자나 문자 그룹 뒤에 옵니다.
메타 문자 목적
? 하나 또는 누락
* 0회 이상
+ 한 번 이상
{N} n번
{N,} n회 이상
{n,m} n회 이상, m회 이하

탐욕스러운 수량자 모드

수량자의 특별한 특징은 탐욕, 초탐욕, 게으름 등 다양한 모드에서 수량자를 사용할 수 있다는 것입니다. 수량자 뒤에 “ ” 기호를 추가하면 초탐욕 모드가 켜지고 +, “ ” 기호를 추가하면 게으른 모드가 켜집니다 ?. 예를 들어:
"A.+a" // greedy mode
"A.++a" // over-greedy mode
"A.+?a" // lazy mode
이 템플릿을 예로 사용하여 다양한 모드에서 수량자가 어떻게 작동하는지 이해해 보겠습니다. 기본적으로 수량자는 탐욕 모드에서 작동합니다. 이는 문자열에서 가능한 가장 긴 일치 항목을 찾는다는 의미입니다. 이 코드를 실행한 결과:
public static void main(String[] args) {
    String text = "Egor Alla Alexander";
    Pattern pattern = Pattern.compile("A.+a");
    Matcher matcher = pattern.matcher(text);
    while (matcher.find()) {
        System.out.println(text.substring(matcher.start(), matcher.end()));
    }
}
다음과 같은 출력을 얻게 됩니다: Alla Alexa 주어진 패턴 " "에 대한 검색 알고리즘은 А.+а다음 순서로 실행됩니다.
  1. 주어진 패턴에서 첫 번째 문자는 러시아 문자입니다 А. Matcher위치 0부터 시작하여 텍스트의 모든 문자와 일치합니다. 텍스트의 위치 0에는 기호가 있으므로 Е패턴 Matcher과 일치할 때까지 텍스트의 문자를 순차적으로 통과합니다. 이 예에서는 5번 위치에 있는 기호입니다.

    Java의 정규 표현식 - 2
  2. 패턴의 첫 번째 문자와 일치하는 항목이 발견되면 Matcher패턴의 두 번째 문자와 일치하는지 확인합니다. .우리의 경우 이것은 모든 문자를 나타내는 기호 " "입니다 .

    Java의 정규 표현식 - 3

    여섯 번째 위치에는 문자 기호가 있습니다 л. 물론 "모든 문자" 패턴과 일치합니다.

  3. Matcher패턴에서 다음 문자를 확인하는 단계로 넘어갑니다. 우리 템플릿에서는 “ ” 수량자를 사용하여 지정됩니다 .+. 패턴에서 “임의의 문자”의 반복횟수는 1회 이상이므로, Matcher“임의의 문자” 조건이 만족하는 한 문자열에서 다음 문자를 차례로 가져와서 패턴에 맞는지 검사하며, 이 예에서는 줄 끝까지(텍스트의 7번 위치부터 18번 위치까지).

    Java의 정규 표현식 - 4

    실제로 Matcher전체 라인을 끝까지 캡처합니다. 여기에서 "탐욕"이 나타납니다.

  4. Matcher텍스트 끝에 도달하고 패턴의 “ ” 부분에 대한 확인을 마친 후 А.+Matcher는 패턴의 나머지 부분(문자 문자 )에 대한 확인을 시작합니다 а. 정방향의 텍스트가 종료되었으므로 마지막 문자부터 시작하여 역방향으로 검사가 수행됩니다.

    Java의 정규 표현식 - 5
  5. Matcher텍스트 끝에 도달한 " " 패턴의 반복 횟수를 "기억 .+"하므로 반복 횟수를 하나씩 줄이고 일치하는 항목을 찾을 때까지 텍스트의 패턴을 확인합니다. Java의 정규 표현식 - 6

매우 탐욕스러운 수량자 모드

슈퍼 욕심 모드에서 매처는 욕심 모드 메커니즘과 유사하게 작동합니다. 차이점은 줄 끝 부분까지 텍스트를 가져오면 뒤로 검색되지 않는다는 것입니다. 즉, 초탐욕 모드의 처음 세 단계는 그리디 모드와 유사할 것입니다. 전체 문자열을 캡처한 후 매처는 나머지 패턴을 추가하고 이를 캡처된 문자열과 비교합니다. 이 예에서는 " " 패턴을 사용하여 기본 메서드를 실행할 때 А.++а일치하는 항목을 찾을 수 없습니다. Java의 정규 표현식 - 7

게으른 수량자 모드

  1. 이 모드에서는 초기 단계에서 Greedy 모드와 마찬가지로 패턴의 첫 번째 문자와 일치하는 항목을 찾습니다.

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

    Java의 정규 표현식 - 9
  3. 게으른 모드는 그리디 모드와 달리 텍스트에서 가장 짧은 일치 항목을 검색하므로 점으로 지정되는 패턴의 두 번째 문자와 일치하는 항목을 찾은 후 텍스트의 6번 위치에 있는 문자와 일치하는 항목을 찾습니다. Matcher텍스트가 나머지 패턴(" а" 문자)과 일치하는지 확인합니다.

    Java의 정규 표현식 - 10
  4. 텍스트의 패턴과 일치하는 항목을 찾을 수 없으므로(텍스트의 7번 위치에 " " 기호가 있음 л) Matcher1회 이상으로 지정되므로 패턴에 또 다른 "모든 문자"를 추가합니다. 그리고 패턴을 5번부터 8번까지의 위치에 있는 텍스트와 다시 비교합니다.

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

    Java의 정규 표현식 - 12
이 방법의 결과로 main" " 템플릿을 사용할 때 А.+?а다음과 같은 결과를 얻게 됩니다. Alla Alexa 예제에서 볼 수 있듯이 동일한 템플릿에 대해 서로 다른 수량자 모드를 사용할 때 다른 결과를 얻었습니다. 따라서 이 기능을 고려하고 검색 중 원하는 결과에 따라 원하는 모드를 선택해야 합니다.

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

Java의 정규식, 더 정확하게는 초기 표현은 문자열 리터럴을 사용하여 지정되므로 문자열 리터럴과 관련된 Java 사양의 규칙을 고려해야 합니다. 특히, \Java 소스 코드의 문자열 리터럴에 있는 백슬래시 문자 " "는 그 뒤에 오는 문자가 특수 문자이므로 특수한 방식으로 해석되어야 함을 컴파일러에 알리는 이스케이프 문자로 해석됩니다. 예를 들어:
String s = "The root directory is \nWindows";//wrap Windows to a new line
String s = "The root directory is \u00A7Windows";//insert paragraph character before Windows
따라서 정규식을 설명하고 " \" 문자(예: 메타 문자의 경우)를 사용하는 문자열 리터럴에서는 Java 바이트코드 컴파일러가 이를 다르게 해석하지 않도록 두 배로 늘려야 합니다 . 예를 들어:
String regex = "\\s"; // template for searching for space characters
String regex = "\"Windows\""; // pattern to search for the string "Windows"
특수 문자를 "일반" 문자로 사용하려는 경우 이중 백슬래시 문자를 사용하여 특수 문자를 이스케이프 처리해야 합니다. 예를 들어:
String regex = "How\\?"; // template for searching the string "How?"

Pattern 클래스의 메서드

클래스에는 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 – 텍스트가 패턴과 일치하는 경우; 거짓 – 그렇지 않으면; 예:
System.out.println(Pattern.matches("A.+a","Alla"));//true
System.out.println(Pattern.matches("A.+a","Egor Alla 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텍스트에서 검색되는 최대 일치 항목 수를 결정합니다.
  • 언제 limit>0– 일치하는 항목 검색이 limit-1수행됩니다.
  • at limit<0– 텍스트에서 일치하는 모든 항목을 검색합니다.
  • when limit=0– 텍스트에서 일치하는 모든 항목을 검색하고 배열 끝에 있는 빈 줄은 삭제됩니다.
예:
public static void main(String[] args) {
    String text = "Egor Alla Anna";
    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);
    }
}
콘솔 출력: Egor Alla Anna -------- Egor Alla Anna 아래에서 객체를 생성하는 또 다른 클래스 메서드를 고려해 보겠습니다 Matcher.

Matcher 클래스 메서드

Matcher패턴을 검색하기 위해 객체가 생성되는 클래스입니다. Matcher– 이것은 정규식의 "엔진"인 "검색 엔진"입니다. 검색하려면 검색 패턴과 검색할 "주소"라는 두 가지 정보가 필요합니다. 개체를 생성하기 위해 Matcher클래스에 다음 메서드가 제공됩니다 Pattern. рublic Matcher matcher(CharSequence input) 메서드는 검색이 수행될 일련의 문자를 인수로 사용합니다. 인터페이스를 구현하는 클래스의 객체입니다 CharSequence. String, 뿐만 아니라 , StringBuffer, StringBuilderSegment도 인수로 전달할 수 있습니다 CharBuffer. 검색 템플릿은 Pattern메소드가 호출되는 클래스 객체입니다 matcher. 매처 생성 예:
Pattern p = Pattern.compile("a*b");// compiled the regular expression into a view
Matcher m = p.matcher("aaaaab");//created a search engine in the text “aaaaab” using 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 = "Egor Alla Anna";
    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) + " с "+ start + " By " + (end-1) + "position");
    }
    System.out.println(matcher.replaceFirst("Ira"));
    System.out.println(matcher.replaceAll("Olga"));
    System.out.println(text);
}
프로그램 출력: 5~8 위치에서 일치 항목이 발견되었습니다. 10~13 위치에서 일치 항목이 발견되었습니다. Anna Egor Ira Anna Egor Olga Olga Egor Alla Anna 예제에서 메소드가 새 객체 (문자열)를 replaceFirst생성한다는 것이 분명합니다. 템플릿과 일치하는 항목이 메서드에 인수로 전달된 텍스트로 대체되는 소스 텍스트입니다. 또한 이 메서드는 첫 번째 일치 항목과 테스트의 모든 일치 항목만 대체합니다. 원본 텍스트는 변경되지 않습니다. 다른 클래스 메소드의 사용 과 정규 표현식의 예는 이 기사 시리즈에서 찾을 수 있습니다 . 텍스트 작업 시 정규식을 사용하는 가장 일반적인 작업은 클래스에서 수행 되며 . , , , 와 같은 메소드입니다 . 그러나 실제로는 "내부적으로" 및 를 사용합니다 . 따라서 불필요한 코드를 작성하지 않고 프로그램에서 텍스트를 바꾸거나 문자열을 비교해야 하는 경우에는 . 고급 기능이 필요하다면 클래스 와 . replaceAllStringreplaceFirstreplaceAllMatcherPatternMatcherStringsplitmatchesreplaceFirstreplaceAllPatternMatcherStringPatternMatcher

결론

정규식은 규칙에 의해 정의된 패턴과 일치하는 문자열을 사용하여 Java 프로그램에서 설명됩니다. 코드가 실행되면 Java는 이 문자열을 클래스 객체로 다시 컴파일하고 Pattern클래스 객체를 사용하여 Matcher텍스트에서 일치하는 항목을 찾습니다. 처음에 말했듯이 정규식은 어려운 주제로 간주되어 나중을 위해 미루는 경우가 많습니다. 그러나 구문, 메타 문자, 이스케이프의 기본 사항을 이해하고 정규 표현식의 예를 연구하면 언뜻 보기보다 훨씬 간단하다는 것을 알 수 있습니다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION