본문 바로가기
프로그래밍/JAVA

초보 자바 프로그래밍(39) - 정규표현식 (Regular Expression)

by 머니테크리더 2023. 5. 2.
반응형

자바 정규 표현식 대표 이미지
자바 정규 표현식 대표 이미지

🔖 INDEX

     

     

    정규 표현식의 주요 요소와 예시

    정규 표현식(Regular Expression)은 문자열 처리 작업에 사용되는 강력한 도구로, 특정 패턴에 일치하는 문자열을 찾거나 대체하는 등의 작업을 수행할 수 있습니다. 정규 표현식은 특수한 문자들로 구성된 문자열로, 각 문자가 특정한 의미를 가지며 이를 조합하여 복잡한 문자열 패턴을 나타낼 수 있습니다.

     

    정규 표현식의 주요 요소와 예시는 다음과 같습니다:

     

    리터럴(Literal)

    리터럴은 문자 그대로의 값을 가지는 문자입니다. 예를 들어, 정규 표현식 'hello'는 문자열 "hello"와 일치합니다. 정규 표현식에서 문자열 "hello"를 찾는 것은 특별한 패턴을 찾는 것이 아니라, 입력된 문자열에서 "hello"라는 문자열이 있는지 확인하는 것입니다.

     

    즉, 정규 표현식 "hello"는 메타문자가 아닌 리터럴 문자들로 구성되어 있습니다. 여기서 'h', 'e', 'l', 'l', 'o'는 모두 리터럴 문자로 간주됩니다.

     

    메타 문자(Meta character)

    정규 표현식에서 특별한 의미를 가지는 문자입니다.

    • . : 임의의 한 문자와 일치합니다. 예를 들어, 정규 표현식 'h.llo'는 "hello", "hallo", "hxllo" 등과 일치합니다.
    • ^ : 문자열의 시작 부분에 일치합니다. 예를 들어, 정규 표현식 '^hello'는 "hello world"와 일치하지만, "world hello"와는 일치하지 않습니다.
    • $ : 문자열의 끝 부분에 일치합니다. 예를 들어, 정규 표현식 'hello$'는 "world hello"와 일치하지만, "hello world"와는 일치하지 않습니다.
    • * : 앞의 문자가 0회 이상 반복된 패턴에 일치합니다. 예를 들어, 정규 표현식 'he*llo'는 "hllo", "hello", "heello", "heeello" 등과 일치합니다.
    • + : 앞의 문자가 1회 이상 반복된 패턴에 일치합니다. 예를 들어, 정규 표현식 'he+llo'는 "hello", "heello", "heeello" 등과 일치하며, "hllo"와는 일치하지 않습니다.
    • ? : 앞의 문자가 0회 또는 1회 반복된 패턴에 일치합니다. 예를 들어, 정규 표현식 'he?llo'는 "hllo"와 "hello"와 일치하며, "heello"와는 일치하지 않습니다.
    • {n} : 앞의 문자가 정확히 n회 반복된 패턴에 일치합니다. 예를 들어, 정규 표현식 'he{2}llo'는 "heello"와 일치하며, "hllo"와 "hello"와는 일치하지 않습니다.
    • {n,m} : 앞의 문자가 n회에서 m회 사이로 반복된 패턴에 일치합니다. 예를 들어, 정규 표현식 `he{1,3}llo`는 "hello", "heello", "heeello"와 일치하며, "hllo"와 "heeeello"와는 일치하지 않습니다.

     

     

    문자 클래스(Character Class)

    대괄호 [] 내에 문자를 나열하여, 해당 문자 중 하나와 일치하는 패턴을 표현합니다.

    • [abc] : "a", "b", "c" 중 하나의 문자와 일치합니다. 예를 들어, 정규 표현식 'h[ae]llo'는 "hallo"와 "hello"와 일치하며, "hillo"와는 일치하지 않습니다.
    • [^abc] : 대괄호 안에서 ^를 사용하면, "a", "b", "c"를 제외한 나머지 문자와 일치합니다.
    • [a-z] : 하이픈(-)을 사용하여 문자의 범위를 지정할 수 있습니다. 이 예에서는 소문자 알파벳 중 하나와 일치합니다.
    • [A-Za-z0-9] : 대문자 알파벳, 소문자 알파벳, 숫자 중 하나와 일치합니다.

     

    미리 정의된 문자 클래스

    일반적으로 사용되는 문자 클래스에 대해 미리 정의된 메타 문자를 사용할 수 있습니다.

    • \d : 숫자와 일치하는 패턴으로, [0-9]와 동일합니다.
    • \D : 숫자가 아닌 문자와 일치하는 패턴으로, [^0-9]와 동일합니다.
    • \s : 공백 문자와 일치하는 패턴으로, 탭, 줄바꿈, 공백 문자 등을 포함합니다.
    • \S : 공백 문자가 아닌 문자와 일치하는 패턴입니다.
    • \w : 단어 문자와 일치하는 패턴으로, 알파벳, 숫자, 밑줄 문자를 포함합니다.
    • \W : 단어 문자가 아닌 문자와 일치하는 패턴입니다.

     

    그룹(Group)

    소괄호 ()를 사용하여 하위 패턴을 그룹화할 수 있습니다. 그룹화를 사용하면 여러 가지 목적으로 활용할 수 있습니다.

    • 그룹 내부의 패턴에 일치하는 문자열을 추출할 수 있습니다.
    • 그룹을 사용하여 연속된 문자에 대해 반복을 적용할 수 있습니다. 예를 들어, 정규 표현식 '(ab)+'는 "ab", "abab", "ababab" 등과 일치합니다.
    • 참조: 그룹에 일치하는 문자열을 다시 사용할 수 있습니다. 예를 들어, 정규 표현식 '(a|b)c\1'는 "aca"와 "bcb"와 일치합니다.

     

    정규 표현식은 이러한 요소들을 조합하여 복잡한 문자열 패턴을 나타낼 수 있습니다. 이를 통해 다양한 문자열 처리 작업을 수행할 수 있으며, 자바뿐만 아니라 다른 프로그래밍 언어에서도 널리 사용됩니다. 정규 표현식을 사용하면 문자열 검색, 치환, 추출, 유효성 검사 등의 작업을 간편하게 처리할 수 있습니다.

     

    예를 들어, 다음 정규 표현식은 이메일 주소의 패턴을 나타냅니다:

    ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}$

     

    이 정규 표현식은 다음과 같은 구성 요소로 이루어져 있습니다.

    1. ^ : 문자열의 시작을 나타냅니다.
    2. [A-Za-z0-9._%+-]+ : 이메일 주소의 사용자 이름 부분으로, 영문 대소문자, 숫자, 마침표, 밑줄, 백분율 기호, 더하기, 마이너스 중 하나 이상의 문자가 들어갑니다.
    3. @ : '@' 기호와 일치합니다.
    4. [A-Za-z0-9.-]+ : 이메일 주소의 도메인 이름 부분으로, 영문 대소문자, 숫자, 마침표, 하이픈 중 하나 이상의 문자가 들어갑니다.
    5. \. : 마침표와 일치합니다.
    6. [A-Z|a-z]{2,} : 이메일 주소의 최상위 도메인 부분으로, 영문 대소문자 중 2개 이상의 문자가 들어갑니다.
    7. $ : 문자열의 끝을 나타냅니다. ​

    이 정규 표현식을 사용하여 주어진 문자열이 올바른 이메일 주소인지 확인할 수 있습니다.

     

    정규 표현식을 사용할 때는 조심해야 할 몇 가지 주의 사항이 있습니다. 정규 표현식이 복잡해질수록 처리 속도가 느려질 수 있으므로, 필요한 경우에만 사용하고 최적화된 패턴을 사용해야 합니다. 또한 정규 표현식은 복잡한 로직을 처리하기에 적합하지 않으므로, 필요에 따라 다른 방법을 고려해야 합니다.

     

     

    자바에서 정규 표현식 사용하기

    자바에서 정규 표현식을 사용하는 방법에 대해 설명하겠습니다. 자바에서 java.util.reggex 패키지는 정규 표현식으로 작업할 수 있는 클래스와 메서드를 제공하여 개발자가 복잡한 텍스트 처리를 필요로 하는 응용 프로그램에서 성능을 활용할 수 있도록 합니다. 정규 표현식을 사용하기 위해서는 java.util.regex 패키지의 Pattern과 Matcher 클래스를 활용합니다.

     

    java.util.reggex 패키지에는 자바에서 정규식으로 작업하기 위한 세 가지 주요 클래스가 포함되어 있습니다:

    1. Pattern: 이 클래스는 컴파일된 정규식 패턴을 나타냅니다. 패턴을 만들고 조작하는 방법과 텍스트와 일치시키는 방법을 제공합니다.
    2. Matcher: 이 클래스는 패턴 개체를 사용하여 텍스트에 패턴 일치를 수행하는 데 사용됩니다. 일치하는 항목을 찾고, 이를 반복하며, 일치하는 하위 문자열 및 그룹을 검색하는 방법을 제공합니다.
    3. PatternSyntaxException: IllegalArgumentException의 하위 클래스입니다. 패턴 문자열에 구문 오류가 있을 때 발생합니다.

    자바에서 정규 표현식으로 작업하려면 먼저 정적 메서드 Pattern.compile()을 호출하여 Pattern 개체를 만들어야 합니다. 이 메서드는 정규 표현식 패턴을 포함하는 문자열을 인수로 사용하고 패턴 개체를 반환합니다:

     

    자바에서 이 정규 표현식을 사용하여 이메일 주소를 검증하는 예제 코드는 다음과 같습니다:

    // 필요한 패키지를 가져옵니다. 정규 표현식을 다루기 위해 java.util.regex 패키지의 Pattern 클래스를 사용합니다.
    import java.util.regex.Pattern;
    
    public class Main {
        public static void main(String[] args) {
            // 검증하려는 이메일 주소를 지정합니다.
            String email = "example.email@test.com";
            
            // isValidEmail 메서드를 사용하여 이메일 주소의 유효성을 검사하고 결과를 boolean 변수에 저장합니다.
            boolean isValid = isValidEmail(email);
    
            // 삼항 연산자를 사용하여 유효성 검사 결과에 따라 "valid" 또는 "invalid" 문자열을 출력합니다.
            System.out.println("Email is " + (isValid ? "valid" : "invalid"));
        }
    
        // 이메일 주소의 유효성을 검사하는 메서드입니다.
        public static boolean isValidEmail(String email) {
            // 이메일 주소를 검사하기 위한 정규 표현식 패턴을 문자열 변수에 저장합니다.
            String emailPattern = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}$";
            
            // Pattern 클래스의 compile 메서드를 사용하여 정규 표현식 패턴을 컴파일합니다.
            // 컴파일된 패턴에 대해 matcher 메서드를 호출하여 이메일 문자열에 대한 Matcher 객체를 얻습니다.
            // matches 메서드를 호출하여 이메일 문자열이 정규 표현식 패턴과 일치하는지 확인하고 결과를 반환합니다.
            return Pattern.compile(emailPattern).matcher(email).matches();
        }
    }

    이 코드는 isValidEmail 메소드를 사용하여 주어진 이메일 주소가 유효한지 확인합니다. 정규 표현식을 사용하여 패턴을 컴파일하고, 이메일 주소 문자열에 대한 Matcher 객체를 얻은 다음, matches() 메소드를 호출하여 이메일 주소가 정규 표현식 패턴과 일치하는지 확인합니다. 결과가 true이면 이메일 주소가 유효하다고 판단하고, 그렇지 않으면 유효하지 않다고 판단합니다.

     

    또한, 주어진 문자열에서 이메일 주소를 찾는 코드는 다음과 같이 작성할 수 있습니다. 하지만, 위의 정규 표현식 패턴에는 문제가 있어서 이메일을 찾지 못합니다. 아래 코드와 같이 ^와 $를 제거하면 이메일 주소를 올바르게 찾을 수 있습니다.

    // 필요한 패키지를 가져옵니다. 정규 표현식을 다루기 위해 
    // java.util.regex 패키지의 Pattern과 Matcher 클래스를 사용합니다.
    import java.util.regex.Pattern;
    import java.util.regex.Matcher;
    
    public class Main {
        public static void main(String[] args) {
            // 검색하려는 문자열을 지정합니다. 이 문자열에는 이메일 주소가 포함되어 있습니다.
            String input = "Hello, my email is john.doe@example.com and my friend's email is jane.doe@example.org";
            
            // 이메일 주소를 검색하기 위한 정규 표현식 패턴을 문자열 변수에 저장합니다.
            // String emailPattern = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}$";
            // 해당 정규표현식으로 변경
            String emailPattern = "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}";
    
            // Pattern 클래스의 compile 메서드를 사용하여 정규 표현식 패턴을 컴파일합니다.
            Pattern pattern = Pattern.compile(emailPattern);
            
            // 컴파일된 패턴에 대해 matcher 메서드를 호출하여 
            // 입력 문자열에 대한 Matcher 객체를 얻습니다.
            Matcher matcher = pattern.matcher(input);
    
            // find 메서드를 사용하여 입력 문자열에서 이메일 주소를 찾습니다. 
            // 이메일 주소가 발견되면 true를 반환하고, 그렇지 않으면 false를 반환합니다.
            while (matcher.find()) {
                // 발견된 이메일 주소를 출력합니다. 
                //matcher.group() 메서드는 현재 찾은 이메일 주소를 반환합니다.
                System.out.println("Found email: " + matcher.group());
            }
        }
    }

    이 코드는 다음과 같은 절차로 동작합니다. ​

    1. import: java.util.regex 패키지의 Pattern과 Matcher 클래스를 가져옵니다.
    2. input: 이메일 주소를 찾을 문자열을 정의합니다.
    3. emailPattern: 이메일 주소를 찾기 위한 정규 표현식을 정의합니다.
    4. Pattern.compile(): 정규 표현식을 Pattern 객체로 컴파일합니다.
    5. pattern.matcher(): Matcher 객체를 생성하여 입력 문자열에 정규 표현식을 적용합니다.
    6. matcher.find(): 입력 문자열에서 정규 표현식에 일치하는 부분을 찾습니다. 일치하는 부분이 있으면 true를 반환하고, 없으면 false를 반환합니다.
    7. matcher.group(): 일치하는 부분을 추출하여 출력합니다. ​

    이렇게 Pattern과 Matcher 클래스를 사용하여 정규 표현식을 적용하고, 일치하는 문자열을 찾거나 추출하는 작업을 수행할 수 있습니다. 이를 통해 문자열 처리 작업을 보다 간편하고 효율적으로 처리할 수 있습니다. 하지만 정규 표현식의 복잡도와 처리 속도에 주의하며 사용해야 합니다. ​

     

    다음은 정규 표현식을 사용하는 몇 가지 실용적인 예제입니다.

     

    전화번호 추출

    // 필요한 패키지를 가져옵니다. 정규 표현식을 다루기 위해 
    // java.util.regex 패키지의 Pattern과 Matcher 클래스를 사용합니다.
    import java.util.regex.Pattern;
    import java.util.regex.Matcher;
    
    public class Main {
        public static void main(String[] args) {
            // 검색하려는 문자열을 지정합니다. 이 문자열에는 전화번호가 포함되어 있습니다.
            String input = "You can call me at (123) 456-7890 or (098) 765-4321.";
            
            // 전화번호를 검색하기 위한 정규 표현식 패턴을 문자열 변수에 저장합니다.
            String phonePattern = "\\(\\d{3}\\)\\s\\d{3}-\\d{4}";
    
            // Pattern 클래스의 compile 메서드를 사용하여 정규 표현식 패턴을 컴파일합니다.
            Pattern pattern = Pattern.compile(phonePattern);
            
            // 컴파일된 패턴에 대해 matcher 메서드를 호출하여 
            // 입력 문자열에 대한 Matcher 객체를 얻습니다.
            Matcher matcher = pattern.matcher(input);
    
            // find 메서드를 사용하여 입력 문자열에서 전화번호를 찾습니다. 
            // 전화번호가 발견되면 true를 반환하고, 그렇지 않으면 false를 반환합니다.
            while (matcher.find()) {
                // 발견된 전화번호를 출력합니다. 
                // matcher.group() 메서드는 현재 찾은 전화번호를 반환합니다.
                System.out.println("Found phone number: " + matcher.group());
            }
        }
    }

    위의 코드는 문자열 내에서 전화번호를 찾는 예제로, 정규 표현식을 사용하여 전화번호가 있는지 확인하고 출력합니다. 주어진 정규 표현식 패턴은 다음과 같은 형식의 전화번호를 찾습니다. ​

    1. 괄호로 둘러싸인 3자리 숫자 (예: (123))
    2. 공백 문자
    3. 하이픈으로 구분된 3자리 숫자
    4. 하이픈으로 구분된 4자리 숫자 ​

     

    예를 들어, (123) 456-7890와 같은 형식의 전화번호를 찾습니다.

     

    URL 추출

    // 필요한 패키지를 가져옵니다. 정규 표현식을 다루기 위해 
    // java.util.regex 패키지의 Pattern 클래스를 사용합니다.
    import java.util.regex.Pattern;
    
    public class Main {
        public static void main(String[] args) {
            // 검증하려는 URL 주소를 지정합니다.
            String url = "https://www.example.com";
            
            // isValidUrl 메서드를 사용하여 URL 주소의 유효성을 검사하고 
            // 결과를 boolean 변수에 저장합니다.
            boolean isValid = isValidUrl(url);
    
            // 삼항 연산자를 사용하여 유효성 검사 결과에 따라 
            // "valid" 또는 "invalid" 문자열을 출력합니다.
            System.out.println("URL is " + (isValid ? "valid" : "invalid"));
        }
    
        // URL 주소의 유효성을 검사하는 메서드입니다.
        public static boolean isValidUrl(String url) {
            // URL 주소를 검사하기 위한 정규 표현식 패턴을 문자열 변수에 저장합니다.
            String urlPattern = "^(https?|ftp)://[a-zA-Z0-9.-]+(\\.[A-Za-z]{2,})?(:\\d+)?(/\\S*)?$";
            
            // Pattern 클래스의 compile 메서드를 사용하여 정규 표현식 패턴을 컴파일합니다.
            // 컴파일된 패턴에 대해 matcher 메서드를 호출하여 URL 문자열에 대한 Matcher 객체를 얻습니다.
            // matches 메서드를 호출하여 URL 문자열이 정규 표현식 패턴과 일치하는지 확인하고 결과를 반환합니다.
            return Pattern.compile(urlPattern).matcher(url).matches();
        }
    }

    위 주석에서는 isValidUrl 메서드가 URL 문자열이 정규 표현식 패턴과 일치하는지 여부를 반환한다는 것을 설명합니다. 이 메서드는 String 타입의 url 매개 변수를 허용하고, 해당 URL이 유효한지를 검사하기 위해 Pattern.compile(urlPattern)을 사용하여 주어진 정규 표현식 패턴을 컴파일합니다. 그런 다음, URL 문자열에 대한 Matcher 객체를 얻기 위해 matcher(url) 메서드를 호출합니다. 마지막으로, matches() 메서드를 사용하여 URL 문자열이 정규 표현식 패턴과 일치하는지 여부를 결정하고 그 결과를 반환합니다.

     

    ​ isValidUrl 메서드의 정규 표현식 패턴은 다음과 같은 구성 요소를 포함합니다.

    1. ^ : 문자열의 시작
    2. (https?|ftp) : "http" 또는 "https" 또는 "ftp" 문자열
    3. :// : "://" 문자열
    4. [a-zA-Z0-9.-]+ : 영문 대/소문자, 숫자, 마침표 또는 하이픈 문자가 한 번 이상 반복되는 도메인 이름
    5. (\\.[A-Za-z]{2,})? : 영문 대/소문자로 된 최상위 도메인(예: .com, .org)을 나타내는 마침표와 두 글자 이상의 문자로 된 하위 도메인이 선택적으로 포함될 수 있습니다.
    6. (:\\d+)? : 선택적으로 콜론과 하나 이상의 숫자가 포함된 포트 번호
    7. (/\\S*)? : 선택적으로 슬래시와 슬래시 다음에 오는 하나 이상의 비공백 문자가 포함된 경로 ​

    위의 구성 요소를 모두 함께 사용하여 유효한 URL 문자열 패턴을 형성합니다. 이 패턴을 사용하면 다양한 형식의 URL 문자열을 검사할 수 있습니다.

     

    주민등록번호 유효성 검사

    다음은 대한민국 주민등록번호를 검증하기 위한 정규 표현식입니다.

    ^[0-9]{6}-?[1-4]\\d{6}$

    위의 정규 표현식 패턴은 다음과 같은 구성 요소를 포함합니다.

    1. ^ : 문자열의 시작
    2. [0-9]{6} : 6자리 숫자로 된 생년월일
    3. [-]? : 생년월일과 개인 식별 번호 사이에 하이픈(-) 문자가 선택적으로 포함될 수 있습니다.
    4. [1-4]\\d{6} : 7자리 숫자로 된 개인 식별 번호(첫 번째 자리는 1부터 4까지의 숫자여야 합니다)
    5. $ : 문자열의 끝 ​

    따라서, 주민등록번호가 위의 패턴과 일치하는지 검사하기 위해서는 Pattern.compile() 메서드를 사용하여 위의 정규 표현식을 컴파일하고, Matcher 객체를 생성하여 해당 문자열과 비교하면 됩니다. 아래는 주민등록번호 유효성 검사를 위한 자바 코드 예시입니다.

    import java.util.regex.Pattern;
    
    public class Main {
        public static void main(String[] args) {
            
            // 검증하고자 하는 주민등록번호
            String jumin = "850101-1234567"; 
            // isValidJumin() 메소드를 사용하여 검증 결과를 받음
            boolean isValid = isValidJumin(jumin); 
    
            System.out.println("주민등록번호 " + jumin + "는 " + (isValid ? "유효합니다" : "유효하지 않습니다"));
        }
    
        public static boolean isValidJumin(String jumin) {
            
            // 주민등록번호 패턴
            String juminPattern = "^[0-9]{6}-?[1-4]\\d{6}$"; 
            
            // 주민등록번호가 패턴과 일치하는지 확인하고 결과를 반환
            return Pattern.compile(juminPattern).matcher(jumin).matches(); 
        }
    }

    위 코드는 주민등록번호가 유효한지를 검사하고, 검증 결과를 출력합니다. isValidJumin 메서드는 매개변수로 받은 주민등록번호가 패턴과 일치하는지 확인하여 결과를 반환합니다.

     

     

    댓글