# [Python] 정규표현식

## 정규표현식

---

- 문자열 처리할 때 나만의 패턴이나, 분석가의 다양한 사례에서 요구하는 조건의 패턴을 만들어서 처리하는 방법

- split, strip, 배웠던 문자열 문법들이 정규표현식과 만나면 정말 다양하게 응용할 수 있다.

- 이메일주소 찾기, 아이디, 비번 패턴 찾기, 회원가입 아이디 패턴 등 다양한 패턴을 만들 수 있다.

- 형식을 지정할 때 정규식을 사용

- 정규표현식을 이용해 정교하게 원하는 데이터 추출/삭제/변환 가능

## 파이썬 정규식

---

- 파이썬에서는 정규 표현식을 지원하기 위해 re(regular expression) 모듈을 제공한다.

- `re.compile`을 사용하여 정규표현식을 컴파일한다.

- `re.compile`과 `re.match`를 한 문장으로 작성할 수 있다.

```javascript
p = re.compile('[a-z]+')
m = p.match("python")
print(m)
```

```javascript
# 축약
m = re.match('[a-z]+', "python")
print(m)
```

| **Method** | **목적** |
| --- | --- |
| match() | 문자열의 처음부터 정규식과 매치되는지 조사 |
| search() | 문자열 전체를 검사하여 정규식과 매치되는지 조사 |
| findall() | 정규식과 매치되는 모든 문자열 substring을 리스트로 리턴 |
| finditer() | 정규식과 매치되는 모든 문자열 substring을 반복 가능한 객체로 리턴 |

```javascript
import re

# 네자리 번호
# abcd, book, desk
# ca?e -> 기억나는 번호
# care, cafe, case, cave -> 가능한 번호
# caae, cabe, cace ,cade, ... -> 너무 많다.

p = re.compile("ca.e") 
# . (ca.e) : 하나의 문자를 의미 > care, cafe, case (O) | caffe (X)
# ^ (^de) : 문자열의 시작 > desk, destination (O) | fade (X)
# $ (se&) : 문자열의 끝 > case, base (O) | face (X)

def print_match(m):

    if m:
        print("m.group():", m.group())   # 일치하는 문자열 반환
        print("m.string:", m.string)     # 입력받은 문자열
        print("m.start():", m.start())   # 일치하는 문자열의 시작 index
        print("m.end():", m.end())       # 일치하는 문자열의 끝 index
        print("m.span():", m.span())     # 일치하는 문자열의 시작/끝 index
    else:
        print("매칭되지 않음")    
        
m = p.match("case") 
# match: 주어진 문자열의 처음부터 일치하는지 확인 
# careless는 care로 매체가 된다.
# print_match(m)
# print(m.group()) # 정규식과 매치되지 않으면 에러가 발생

m = p.search("good care") # search: 주어진 문자열 중에 일치하는게 있는지 확인
print_match(m)
# lst = p.findall("good care cafe") # findall: 일치하는 모든 것을 리스트 형태로 반환
# print(lst)
```

```javascript
m.group(): care
m.string: good care
m.start(): 5
m.end(): 9
m.span(): (5, 9)
# ['care', 'cafe']
```

## 정규표현식 라이브러리 함수

---

**Match** 

- 문자열 처음부터 정규식과 매칭되는 패턴을 찾아서 리턴

- m = p.match("비교할 문자열"): 주어진 문자열의 처음부터 일치하는지 확인

**Search**

- 문자열 전체를 검색해서 정규식과 매칭되는 패턴을 찾아서 리턴

- m = p.search("비교할 문자열"): 주어진 문자열 중에 일치하는게 있는지 확인

**Findall**

- 정규표현식과 매칭되는 모든 문자열을 리스트 객체로 리턴

- lst = p.findall("비교할 문자열"): 일치하는 모든 것을 "리스트" 형태로 반환

**Split**

- 찾은 정규표현식 패턴 문자열을 기준으로 문자열을 분리

**Sub**

- 찾은 정규표현식 패턴 문자열을 다른 문자열로 변경

## 메타문자

---

### . (Dot)  ^,  $

### .(dot)

- 줄바꿈 문자인 `\n`을 제외한 모든 문자와 매치

- `re.DTALL` 옵션을 주면 `\n` 문자도 매치된다.

**예시 - **`**a.b**`

- a와 b 사이에 어떤 문자가 와도 매치된다.

- aab: a와 b 사이에 a가 위치하므로 정규식과 매치

- a0b: a와 b 사이에 0이 위치하므로 정규식과 매치

- abc: a와 b 사이에 문자가 존재하지 않으므로 매치되지 않는다.

**예시 - a[.]b**

- `a.b`: a와 b 사이에 .가 위치하므로 정규식과 매치

- `a0b`: a와 b 사이에 0이 위치하므로 매치되지 않는다.

### ^

- 문자열의 시작

- (^de) : desk, destination (O) | fade (X)

- 문자열의 맨 처음과 일치한다는 것을 의미

- `re.MULTILINE`을 사용할 경우 여러 줄의 문자열일 때 각 줄의 처음과 일치

```javascript
re.search('^Life', 'Life is too short')  # 매치         - Match 객체
re.search('^Life', 'My Life')            # 매치되지 않음 - None
```

### $

- 문자열의 끝

- (se&) : case, base (O) | face (X)

- & 메타 문자와 반대의 경우

- 문자열의 끝과 매치

```javascript
re.search('short$', 'Life is too short')                  # 매치 - Match 객체
re.search('short$', 'Life is too short, you need python') # 매치되지 않음 - none
```

### 반복

?는 앞 문자가 0번 또는 1번 표시되는 패턴

*는 앞 문자가 0번 또는 그 이상 반복되는 패턴

+는 앞 문자가 1번 또는 그 이상 반복되는 패턴

{n}는 앞 문자가 n번 반복되는 패턴

{m, n}는 앞 문자가 m번 반복되는 패턴부터 n번 반복되는 패턴까지

### ?

- 반복은 아니지만 {}와 비슷한 기능을 한다.

- ? 메타 문자가 의미하는 것은 `{0, 1}` - 있어도 되고 없어도 된다.

**예시 - **`**ab?c**`

- abc: b가 1번 반복되어 매치

- ac: b가 0번 반복되어 매치

### *

- 바로 앞에 있는 문자가 0부터 무한대까지 반복될 수 있다는 의미

- 무한대까지라고 표현되어있지만, 실제로는 메모리 용량의 한계로 약 2억개라고 한다.

**예시 - **`**ca*t**`

- ct: a가 0번 반복되어 매치

- cat: a가 1번 반복되어 매치

- caaat: a가 3번 반복되어 매치

### +

- 최소 1번 이상 반복될 때 사용

- *는 반복 횟수가 0부터, +는 반복 횟수가 1부터이다.

**예시 - **`**ca+t**`

- ct: a가 0번 반복되어 매치되지 않음

- cat: a가 1번 반복되어 매치

- caaat: a가 3번 반복되어 매치

### **{}**

- 반복 횟수를 고정

- `{n}`: 반복 횟수가 n번인 문자와 매치

- `{m, n}`: 반복 횟수가 m부터 n까지인 문자와 매치

- 반복횟수는 생략도 가능하다.

    - `{2, }`: 반복 횟수가 2 이상인 경우

    - `{, 3}`: 반복 횟수가 3 이하인 경우

**반복되는 값을 지정하여 패턴을 찾을 수도 있다.**

- 정규표현식은 여러 개 합쳐서 사용 가능하다.

### 괄호와 하이픈

- [] 괄호 안에 들어가는 문자가 들어 있는 패턴
- Ex) [abc] 는 a, b, c 중 하나가 들어 있는 패턴을 의미

- 하이픈(-)을 이용하면 알파벳 전체를 나타낼 수 있음
- Ex) [a-c] 는 a, b, c 중 하나가 들어 있는 패턴을 의미

- () 괄호는 괄호 안에 있는 단어 자체를 반환함
- Ex) (abc) 는 abc가 들어 있는 패턴을 의미

![Image](https://upload.cafenono.com/image/slashpagePost/20250201/170647_uJ5QdGrJXwHvd7KIXQ?q=80&s=1280x180&t=outside&f=webp)

### [ ]

- 문자 클래스 character calss

- ‘[’와 ‘]’ 사이의 문자들과 매치

- 문자 클래스를 만드는 메타 문자인 [] 사이에는 어떤 문자도 들어갈 수 있다.

- 하이픈(-)을 사용하면 두 문자 사이의 범위를 나타낸다.

    - [a-zA-Z]: 모든 알파벳

    - [0-9]: 모든 숫자

    - 한글 [가-힣]

    - 자음 모음 [ㄱ-ㅎ] [ㅏ-ㅣ]

**자주 사용하는 문자 클래스**

- `\d` : 숫자와 매치, `[0-9]`와 동일

- `\D` : 숫자가 아닌 것과 매치 `[^0-9]`와 동일

- `\s` : 화이트스페이스 whitespace 문자와 매치 `[ \t\n\r\f\v]`와 동일

- `\S` : 화이트스페이스 문자가 아닌 것과 매치 `[^ \t\n\r\f\v]`와 동일

- `\w` : 문자+숫자와 매치 `[a-zA-Z0-9_]`와 동일

- `\W` : 문자 + 숫자가 아닌 문자와 매치 `[^a-zA-Z0-9_]`와 동일

### |

- or과 동일한 의미

- A|B: A 또는 B

```javascript
p = re.compile('Crow|Servo')
m = p.match('CrosHellow')
```

### \A

- 문자열의 처음과 매치된다.

- ^ 매타 문자와 동일한 의미, `re.MULTILINE` 옵션 사용할 경우 다르게 해석

    - ^: 각 줄의 문자열의 처음

    - \A: 줄과 상관 없이 전체 문자열의 처음

### \Z

- 문자열의 끝과 매치된다.

- `re.MULTILINE` 옵션을 사용할 경우 $ 메타 문자와는 달리 전체 문자열의 끝과 매치

### \b

- 단어 구분자 word boundary

- 화이트스페이스에 의해 구분된다.

```javascript
p = re.compile(r'\bclass\b')
p.search('no class at all')

p.search('the declassified algorithm')

p.search('one subclass is')
```

## Group 그루핑

---

- 그룹을 만들어주는 메타문자는 `()`이다.

- 보통 반복되는 문자열을 찾을 때 그룹을 사용

- 그룹을 사용하는 더 중요한 이유는 매치된 문자열 중에서 특정 부분의 문자열만 뽑아내기 위해서이다.

| **group (인덱스)** | **설명** |
| --- | --- |
| group(0) | 매치된 전체 문자열 |
| group(1) | 첫 번째 그룹에 해당되는 문자열 |
| group(2) | 두 번째 그룹에 해당되는 문자열 |
| group(3) | n 번쨰 그룹에 해당되는 문자열 |

**그루핑된 문자열 재참조**

- 그루핑한 문자열을 재참조 backreferences 할 수 있다.

- 2개의 동일한 단어를 연속적으로 사용해야만 매치가 된다.

    - `\1`: 재참조 메타 문자

    - `\2`: 두 번째 그룹 참조

**그루핑된 문자열에 이름 붙이기**

- 정규식 안에 그룹이 다수 존재한다면 혼란스러울 것이다.

- 이름으로 참조할 수 있다면 문제 해결 가능

- 재참조 시에는 (?P=그룹이름)이라는 확장 구문 사용

## str

---

### **[strip(to_strip=None)](https://pandas.pydata.org/docs/reference/api/pandas.Series.str.strip.html)**

- 문자열 및 공백 제거

- 선행과 후행 문자가 제거된 문자열의 복사본을 돌려준다.

- to_strip 인자는 제거할 문자 집합을 지정

    - 생략되거나 none이라면 기본값은 공백을 제거

    - to_strip 인자는 접두사가 아니다.

**lstrip()**

- 선행 문자만 지울 때 사용

**rstrip()**

- 후행문자만 지울 때 사용

### **[str.center(width, fillchar=' ')](https://pandas.pydata.org/docs/reference/api/pandas.Series.str.center.html#pandas.Series.str.center)**

- 정의된 문자열을 앞뒤로 특정문자로 채운 뒤 중앙에 정렬하는 방법

**ljust()**

- 왼쪽 정렬

**rjust()**

- 오른쪽 정렬

### [*](https://pandas.pydata.org/docs/reference/api/pandas.Series.str.split.html#pandas.Series.str.split)_[str.split(pat=None, ](https://pandas.pydata.org/docs/reference/api/pandas.Series.str.split.html#pandas.Series.str.split)__[, n=-1, expand=False, regex=None)](https://pandas.pydata.org/docs/reference/api/pandas.Series.str.split.html#pandas.Series.str.split)_

- sep를 구분자로 문자열로 사용하여 문자열에 있는 단어들의 리스트를 돌려준다.

- maxsplit가 주어지면 최대 maxsplit 번의 분할이 수행

### 대소문자 바꾸기

- lower: 소문자로 변경

- upper: 대문자로 변경

- cappitalize: 앞문자 대문자로 변경

- title: 단위별 앞문자 대문자로 변경

- swapcase: 소문자는 대문자, 대문자는 소문자로 변경

### **[str.replace(pat, repl, n=-1, case=None, flags=0, regex=False)](https://pandas.pydata.org/docs/reference/api/pandas.Series.str.replace.html#pandas.Series.str.replace)**

- 모든 서브스트링 old 가 new 로 치환된 문자열의 복사본을 돌려준다.

- 선택적 인자 count 가 주어지면, 앞의 count 개만 치환

### **[str.find(sub, start=0, end=None)](https://pandas.pydata.org/docs/reference/api/pandas.Series.str.find.html#pandas.Series.str.find)**

- 서브스트링 sub가 슬라이스 내에 등장하는 가장 작은 문자열의 인덱스를 돌려줍니다.

- 선택적 인자 start 와 end 는 슬라이스 표기법으로 해석됩니다.

- sub이 없으면 -1을 돌려줍니다.

### **[str.slice(start=None, stop=None, step=None)](https://pandas.pydata.org/docs/reference/api/pandas.Series.str.slice.html#pandas.Series.str.slice)**

- 특정 인덱스의 값을 잘라내어 반환

- slice_replace: 해당 사이의 인덱스 값을 다른 값으로 바꾼다.

For the site tree, see the [root Markdown](https://slashpage.com/yerim-devnote.md).
