ysk(0soo) 2022. 8. 31. 14:28

유튜브 우아한 Tech 채널에서 10분 테코톡을 듣고 공부한 내용입니다.

정규표현식

목차

  1. 정규표현식의 이해
  2. 정규표현식의 활용
  3. Java에서 정규표현식의 활용

정규표현식의 이해

정규표현식 : Regular Expression, RegExp , Regex

정규 표현식은 줄여서 정규식이라고도 하며, 영어로는 Regular Expression, 줄여서 regex, regexp라고도 한다.
초반에는 편집기의 패턴매칭을 시작으로 사용되었으며, 수학적인 의미에서 시작되었다고 하며,
특정한 규칙을 가진 문자열의 집합을 표현하기 위해 쓰이는 형식언어이다.

수학자 Stephen Cole Kleene에 의해 생성됐으며

편집기의 패턴 매칭을 시작으로 사용.

grep 명령어가 정규표현식을 사용한다.

Vi, emacs 같은 편집기나, sed, awsk 같은 유닉스 명령어에 정규 표현식이 추가

이후 IDE와 여러 프로그래밍 언어의 표준 라이브러리로 지정됐다

정규표현식의 메타문자 : 문자를 나타내는 문자

  • . : 모든문자

  • [] : 대괄호 안에 들어가있는 문자를 찾음. 대괄호 안에서 ^은 not을 의미: [^a ]

  • | : or 또는

  • \s : 공백

  • \d : [0-9] 숫자 0부터 9까지

  • \w : [0-9a-zA-Z_] 영문자, 숫자 ,밑줄

정규표현식의 수량자 : 앞 문자의 갯수

  • ? : 앞문자가 없거나 하나 있음. ({0, 1})
  • + : 앞 문자가 하나 이상({0, 1})
  • * : 앞 문자가 0개 이상 ({0,})
  • {n, m} : 앞문자가 n개이상 m개 이하
  • {n,} : 앞 문자가 n개 이상. 위의 형태에서 m이 생략된 형태
  • {n} : 앞문자가 n개
정규표현식 = 패턴구분자 시작 ( /) + 작성할 패턴 (패턴) + 패턴 구분자 끝 (/) + 패턴 변경자 (g)
= /패턴/g
  • . 은 모든 문자를 의미
    • [.CU]는 ., .C, .CU, U, CU 등을 찾는다.
  • ^은 not을 의미
    • [^.CU]는 ., .C, .CU, U, CU 을 제외한 모든 문자를 찾는다

  • Thank 또는 3 또는 . .문자를 찾는다

  • \s|\w
    • \s (공백) | (또는) \w (영문자 모두, 숫자, 밑줄)을 찾는다
  • \d|[A-Za-z]
    • 숫자 모두 또는 영 소,대문자 모두를 찾는다

  • 1로 시작하거나 숫자인 경우 이거나 대문자 A-Z

  • w와 wa 이거나 ,로 시작하여 ,로 끝나는 문자열

  • 메타문자와 수량자를 구분해서 정규표현식을 파악하자
    • -?는 -가 있거나 없을 수 있다
  • ^ 부터 $ 까지 패턴에 맞는 애들만 찾는다.
  • 첫번째 앞에 2개 또는 3개의 숫자,
  • 2번째 -부터 3개 또는 4개의 숫자
  • 3번째 -부터 4개인 숫자만 찾는 패턴
    • 패턴에 맞는 010-1234-1234만 찾는다.

항상 정규표현식을 사용하는게 좋은가?

강점: 패턴으로 검증이 가능하다. if문을 많이 안써도 된다.

약점: 가독성이 나쁘다. 유지보수하기 힘들다.

그러므로, 간단한 검증일때는 if문으로, 복잡한 검증일때는 정규식으로 하되, 주석을 통해서 가독성을 높이는 것이 필요하고 중요하다.

  • 어떤 정규표현식이 주석을 달아 설명해주자

정규표현식은 어디에 쓰일까?

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

개발도구에서의 문자열 치환

ex ) 다음과 같은 인덱스 들이 있을 때 인덱스 이름 앞에 idx_를 넣어주고싶다면?

CREATE INDEX `comment_post` on `comment` (post_id);
CREATE INDEX `mail_auth_email` on `mail_auth` (email);
  • pattern : ([^]+)` on : 백틱을 제외한다
  • replace String : idex_$1 on
CREATE INDEX `idx_comment_post` on `comment` (post_id);
CREATE INDEX `idx_mail_auth_email` on `mail_auth` (email); 
  • `([^`]+)` on `로 시작하는  문자열을
    `idex_$1` on 으로 replace 한다

java에서의 정규표현식의 활용

  1. 문자열에서 알파벳 대문자, 숫자, 더하기(+), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거하라
  2. 문자열에서 마침표(.)가 3번 이상 연속된 부분을 하나의 마침표(.)로 치환하라
private String removeChar(String input) {
  return input.replaceAll("[^A-Z0-9+_.]", ""); // 1번. 제거
}

private String changeDot(String input) {
  return input.replaceAll("[.]{3,}", "."); // 2번 .로 replace
}

String Class의 replaceAll() 메서드

public String replaceAll(String regex, String replacement) {  
  return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
  • Pattern.compile()을 사용하고 있다.
/// Pattern.compile() 메서드


/**
 * Compiles the given regular expression into a pattern.
 *
 * @param  regex
 * The expression to be compiled
 * @return the given regular expression compiled into a pattern
 * @throws  PatternSyntaxException
 *          If the expression's syntax is invalid
*/
public static Pattern compile(String regex) {      
  return new Pattern(regex, 0);
}
  • 항상 패턴으로 새로운 패턴을 만든다. (new)
  • 사실상 패턴을 바뀔일이 없으므로 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("");
}

private String changeDot(String input) {
  return CHANGE_DOT_PATTERN.matcher(input).repliaceAll(".");
}

Pattern 클래스는 정적 팩토리 메서드를 사용하고 있으며 Thread-safe 하다

Pattern 객체는 불변 객체이다.

Matcher 클래스 사용시 주의할점

Matcher 객체는 reset() 하고 다시 input 값을 넣어서 재사용해줄 수 있지만 Thread-safe 하지못하다.

  • Matcher Class의 reset() 메서드
/**  
* Resets this matcher. 
* <p> Resetting a matcher discards all of its explicit state information  
* and sets its append position to zero. The matcher's region is set to the    
* default region, which is its entire character sequence. The anchoring
* and transparency of this matcher's region boundaries are unaffected.
*  
* @return  This matcher
*/
public Matcher reset() {
  ...
    return this;    
}

그러므로 Thread-safe 하게 사용하려면 Pattern 객체의 matcher()를 통해 Matcher를 새로 생성한 뒤 사용하자

정규표현식은 평생 개발을 하더라도 모든 정규 표현식을 외우는 일은 드물다고 한다.

알고리즘 처럼 감을 잃지 않도록 하는게 중요하다

IDE에서 문자열을 replace 할 일이 있을 때 정규 표현식을 사용하여 연습하는것이 중요

참조