열심히 끝까지

[10분 테코톡] 빙봉의 정규표현식 본문

디바이스 융합 자바(Java)기반 풀스택 개발자 양성과정(과제)

[10분 테코톡] 빙봉의 정규표현식

노유림 2022. 7. 23. 01:45

[10분 테코톡]
정규 표현식 - 빙봉
https://www.youtube.com/watch?v=CjoDIgDOHA4&t=3s

1. 정규표현식의 이해
    - 정규표현식(규식)
       : 1951년도 제작
       : 수학자 Stephen Cole Kleene에 의해 제작
    > 초기에는 수학적인 개념으로 탄생

    >> 사용되게 된 순서
      1. 편집기의 패턴 매칭을 시작으로 사용
      2. grep 명령어가 정규표현식을 사용 -> 발전 시작
      3. vi, emacs 같은 편집기나 sed, awk같은 유닉스 명령어에도 정규표현식 추가
      4. 이후 IDE와 여러 프로그래밍 언어의 표준 라이브러리로 지정

    >> 능력
      - 특정 패턴을 가지고 문자열을 찾을 수 있음
       ex ) 전화번호 유효성 검증 요구사항
              1. 맨 앞의 번호는 010으로 시작
              2. 대시("-")로 구분
              3. 구분된 숫자에는 4자리의 숫자가 와야 함

                : 정규표현식이 없는 경우
                     if문으로 유효성체크 진행
                         > 하다보면 if문이 엄청 많이 생기게 됨

               : 정규표현식이 있는 경우
                     한줄로 마무리가 됨
                     > regex : "010-\\d{4}-\\d{4}"

     - 정규표현식 = 패턴구분자 시작 + 작성할 패턴 + 패턴구분자 끝 + 패턴 변경자
                                     /                    패턴                /                      g
            >> 언어마다 다르지만 이번에 Java Script위주로 진행
                  > 모든 것이 될 수 있는데 대부분 슬레쉬(/)로 사용
                  > 패턴 위주로 설명

         > 메타문자 : 문자를 나타내는 문자
               . : 모든 문자 
                     ex)  /./g

              [] : 대괄호 안에 들어가는 문자를 찾음. 대괄호 안에서 ^는 not을 의미 
                     ex) /[.CU]/g : . C U의 글자를 찾음  
                          /[^CU]/g : . C U의 글자를 제외한 모든 것을 찾음
               | : or
                    ex) /Thank|3|\.\./g : Thank, 3, . . 을 찾음

            \s : 공백
           \d : [0-9]
           \w : 영문자 모두, 숫자, 밑줄[0-9a-zA-Z]
                    ex) /\3|\w/g : . , !를 제외한 모든 것(공백, 영문자 모두, 숫자 밎줄)을 찾음
                        /\d|[A-Za-z]/g : 숫자, 영문자 모두를 찾음
         -------------------------------------------
         > 수량자 : 앞 문자의 개수
              ? : 앞 문자가 없거나 하나 있음 ({0,1}) 
                  혹은 처음 발견했을 때 쉬고 다시 찾음
                   ex) /wa?|,.*,/g : 소문자 w와 a뒤에 ?가 오면
                                        앞 문자가 있거나 없으면 w하나만 찾고 있으면 wa까지 같이 찾음
                                        + ,뒤에 .*가 오고 ,이 오면 ,부터 ,까지의 모든 문장을 찾음.
                                          , a, b, c, d, e라고 한다면, ,a, b, c, d,까지 찾음
                        /wa?|,.*?,/g : 근데 .*뒤에 ?가 오고나서 ,이 오면 처음 발견하고 
                                          바로 찾지 않고 쉬고 찾음
                                          , a, b, c, d, e  라고 한다면 , a, , c, , e,를 찾음

             + : 앞 문자가 하나 이상({1, }) 
              * : 앞 문자가 0개 이상임({0, })
                   ex) /o{1}|\d+|[A-Z]a*/g 
                       : 소문자 o{1}(영문자 o의 하나), 숫자 하나 이상, 영문자 모두 중 소문자a가 0개 이상을 찾음
 
       {n, m} : 앞 문자가 n개 이상, m개 이하
         {n, } : 앞 문자가 n개 이상, 위의 형태에서 m이 생략된 형태
           {n} : 앞 문자가 n개 
                  ex) /o{1}|\d{1, }|[A-Z]a{0, }/g
                      : 1보다 크면 +와 동일, 0보다 크면 *와 동일

              ^ : 찾으려는 문자열의 처음을 뜻함 
              $ : 찾으려는 문자열의 끝을 뜻함
                 ex) /^\d{2,3}-?\d{3,4}-?\d{4}$/g
                      : 이 패턴과 동일한 친구만 찾음

      - 전화번호 정규표현식 분석
           : 메타문자와 수량자를 잘 파악!
        > /\d{2,3}-?\d{3,4}-?\d{4}/g
         메타문자 : \d - \d - \d
         수량자 : {2,3} ? {3,4} ? {4}
  
  > 정규표현식을 사용하는 것이 좋은가?
     : 아니다!
     - 정규표현식의 강점
          : 패턴으로 검증 가능, if문을 많이 쓰지 않아도 됌
     - 정규표현식의 약점
          : 너무 안 좋은 가독성, 유지보수하기 어려움

  >> 해결방안--------------------------------
       간단한 검증일 때는 if문으로 해결
       메서드 명을 통해 가독성을 높이기
       복잡한 검증이 있을 때만 정규표현식 사용
       주석을 달아서 가독성을 높이기

2. 정규표현식의 활용
    - 정규표현식이 쓰이는 곳
     1. 컴파일러의 파서
     2. CLI환경을 주로 사용하는 경우, grep, sed, awk를 통해 쓰임
     3. 이메일, 주소, 전화번호 규칙 검증
     4. 입력에서 불필요한 입력 검증 
     5. 개발도구에서 문자열 치환
     6. 로깅에서 찾아볼 때,
     7. 코딩 테스트
    > 5,7 위주로 설명

  - 5. 개발도구에서 문자열 치환
       : Intelliji는 정규표현식 문자열 치환을 지원
            Window : Ctrl + r
            Mac : command + r

     : 인덱스 이름 앞에 idx_를 넣어주고 싶으면?
           > Pattern : '([^']+)' ON
              Replace String : 'idx_$1' ON

3. Java에서 정규표현식의 활용(코딩테스트에서 수정해서 가져옴)
    1. 문자열에서 알파벳 대문자, 숫자, 더하기(+), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거하라
    2. 문자열에서 마침표(.)가 3번 이상 연속된 부분을 하나의 마침표(.)로 치환하라
   Private String removeChar(String input){
      return input.replaceAll(regex:"[^A-Z0-9+_.]", replacement: "");
   }
   Private String changeDot(String input){
      return input.replaceAll(regex:"[.]{3,}", replacement: ".");
   }
------------
   public String replaceAll(@NOTNULL String regex, @NOTNULL String replacement){
      return Pattern.compile(regex).matcher(input:this).replaceAll(replacement);
   }
------------
   public static Pattern compile(@NonNis NotNull String regex){
      return new Pattern(regex, f:0);
   }

---------------------------
   >> String의 replaceAll을 사용할 땨, Pattern을 정적으로 만들자!
   private static final Pattern REMOVE_CHAR_PATTERN=Pattern.compile("[^A-Z0-9+_.]");
   private static final Pattern CHANGE_DOT_PATTERN=Pattern.compile("[.]{3,}");
   private String removeChar(String input){
      return REMOVE_CHAR_PATTERN.matcher(input).replaceAll(replacement:"");
   }
   private String changeDot(String input){
      return CHANGE_DOT_PATTERN.matcher(input).replaceAll(replacement:".");
   }   
  
  >> Pattern 객체는 불변 객체!
       : Pattern 클래스는 정적 팩토리 메서드를 사용하고 있으며 Thread-safe함!

 - Matcher 클래스 사용 시 주의할 점
  : Matcher 객체는 reset()하고 다시 input을 넣어 재사용해줄 수 있지만
   Thread-safe하지 못함.
  : Thread-safe하게 사용하려면 Pattern 객체의 matcher()을 통해 Matcher을 생성한 뒤 사용

---------------
 - 정규표현식을 어떻게 학습하면 좋을까?
  1. 정규표현식의 현실, 21년 차 개발자도 모든 정규표현식을 외우고 있지 않다고 함
  2. 알고리즘처럼 감을 잃지 않도록 하는 게 중요하다고 생각
  3. IDE에서 문자열을 replace할 일이 있을 때, 정규표현식을 사용해 연습!
  4. 혹시나 정규표현식을 마주했다면 분석하기

>> 요약
   1. 클린코드를 위해 정규표현식을 사용할 때는 고민하고 사용
   2. 정규표현식을 분석하는데 핵심은 메타문자와 수량자 파악
   3. Java에서 정규표현식을 사용할 때는 Pattern은 변하지 않으므로 정적으로 만들기
   4. Java의 Matcher 객체는 Thread safe하지 못함.
      멀티스레드 환경이라면 Pattern의 matcher()를 사용하기
   5. 정규표현식은 그때 그때 알아보기