본문 바로가기

Programming/Python

[Python] 문자열 치환 메서드 성능 비교 - str.replace(), re.sub(), str.translate()

https://cuffyluv.tistory.com/120

 

[Python/leetcode] 819. Most Common Word

https://leetcode.com/problems/most-common-word/description/가장 흔한 단어.금지된 단어를 제외하고, 가장 흔하게 등장하는 단어를 출력해라. 대소문자 구분을 하지 않으며, 구두점(마침표, 쉼표 등) 또한 무시

cuffyluv.tistory.com

- 해당 문자열 치환 문제를 풀고 정리하면서, 같은 문제를 `str.replace`, `re.sub`, `str.translate` 세 함수 및 메서드 모두로 풀 수 있음을 확인하였다.

- 따라서, 저 세 함수 및 메서드 각각을 어떤 상황에 사용해야 할지 그 특성과 장단점 및 성능을 비교해 정리해보고자 한다.

  1. str.replace()
  2. str.translate()
  3. re.sub()

1. str.replace()

단순한 문자열 치환 작업에 사용.

문법

result = str.replace(old, new[, count])

매개변수

1. old (필수)

- 교체하고자 하는 부분 문자열.

- old가 원본 문자열에 존재하지 않으면 -> 아무 일도 일어나지 않고, 원본 문자열이 그대로 반환됨.

- old가 원본 문자열에 존재하면 -> 교체된 문자열이 반환됨.

"hello world".replace("world", "Python") # "hello Python"

2. new (필수)

- `old`를 대체할 새로운 부분 문자열.

- 빈 문자열`"" 또는 ''`로 설정하면 -> old를 삭제하는 효과가 있음.

"hello world".replace("world", "")  # "hello "

3. count (선택, default = None)

- 교체할 최대 횟수를 지정.

- `count`가 생략되면 -> 문자열 내 존재하는 모든 `old`가 교체됨. 

- `count`가 지정되면 -> 왼쪽부터 시작하여 최대 `count`번 교체가 수행됨.

"hello world world".replace("world", "Python", 1)  # "hello Python world"

반환값

- `str.replace()`는 새로운 문자열을 반환함.

- old가 원본 문자열에 없으면 -> 원본 문자열을 그대로 반환.

예제

1. 기본 사용

text = "hello world"
result = text.replace("world", "Python")
print(result)  # "hello Python"

2. count 매개변수 사용

text = "apple banana apple grape apple"
result = text.replace("apple", "fruit", 2)
print(result)  # "fruit banana fruit grape apple"

3. 부분 문자열 제거

text = "remove this part"
result = text.replace("remove ", "")
print(result)  # "this part"

4. 제거할 문자열이 없는 경우

text = "hello world"
result = text.replace("universe", "Python")
print(result)  # "hello world" (변경 없음)

5. URL 정리

url = "https://www.example.com/page.html"
clean_url = url.replace("https://", "").replace("www.", "")
print(clean_url)  # "example.com/page.html"

6. 구두점을 공백으로 변환

# replace를 사용해 구두점을 공백으로 대체.
for c in string.punctuation:
paragraph=paragraph.replace(c," ")

장점

- 단순한 문자열 치환 작업에 좋음.

- 코드가 직관적이고 사용하기 쉬움.

- 메서드가 C로 구현되어 있어 속도가 빠름.

- 단순 문자열 교체를 원한다면 `str.replace()`가 제일 적합한 선택.

단점

- 복잡한 패턴 매칭을 해결하기는 어려울 수 있음. -> `re.sub()` 사용

- 여러 개의 문자열을 각각 다른 문자열로 교체하려면, 순차적으로 replace()를 여러번 호출해야돼서 성능이 떨어짐.

여러 개의 문자열을 교체하는 방법

1. `.`을 사용해 순차적으로 replace() 호출

text = "apple banana orange grape"

# 여러 문자열을 순차적으로 교체
result = text.replace("apple", "red").replace("banana", "yellow").replace("orange", "orange")
print(result)  # "red yellow orange grape"

구현하기 간단하나, 코드가 길어질 수 있음.

2. 문자열 매핑을 딕셔너리로 정의 후 반복문 사용

text = "apple banana orange grape"

# 교체할 문자열 매핑
replacements = {
    "apple": "red",
    "banana": "yellow",
    "orange": "orange"
}

# 반복적으로 문자열 치환
for old, new in replacements.items():
    text = text.replace(old, new)

print(text)  # "red yellow orange grape"

* 주의) Python 3.6 이전 버전은 딕셔너리가 저장 순서를 유지하지 않으므로, 치환 순서가 중요하다면 `OrderedDict`를 사용해야함. 근데 대부분은 3.7 이상 버전 쓰니까 노상관.


2. str.translate() 및 str.maketrans()

다수의 문자 치환에 사용.

문법

tabel = str.maketrans(x[, y[, z]])
result = str.translate(table)

매개변수

1. x (필수)

- 각 치환 대상 문자들로 이루어진 문자열.

2. y (필수)

- 각 치환 결과 문자들로 이루어진 문자열.

- `x`와 같은 길이를 가져야 하며, `x`의 각 문자를 `y`의 대응 문자로 치환하게됨.

3. z (선택)

- 각 삭제 대상 문자들로 이루어진 문자열.

- `z`에 포함된 모든 각 문자는 매핑 테이블에 의해 None으로 설정되어 문자열에서 삭제됨.

- 이 때, 삭제되고 그 자리에 공백이 남는 것이 아닌, 아예 그냥 지워짐(공백을 남기지 않음).

4. table (필수)

- 문자 변환 규칙을 정의하는 매핑 테이블.

- 주로 `str.maketrans()` 메서드로 생성된 테이블을 사용.

- 또는, `ord()` 함수를 사용해 딕셔너리 형태로 직접 정의한 테이블을 사용할 수도 있음.

반환값

- `str.maketrans()`는 우리가 정의한 매핑 테이블을 반환함. 자료형은 `dict`

- 이 때, 문자 대신 유니코드 코드 포인트가 출력됨.

매핑 테이블은 문자를 유니코드 코드 포인트로 변환하여 저장하기 때문.

- `str.translate()`는 새로운 문자열을 반환함.

table = str.maketrans('abc', '123')
print(table)

# {97: 49, 98: 50, 99: 51}
table = str.maketrans("abc", "123", "xyz")
print(table)

# {97: '1', 98: '2', 99: '3', 120: None, 121: None, 122: None}

예제

1. 문자 변환만 수행

# 'a'->'1', 'b'->'2', 'c'->'3'
table = str.maketrans("abc", "123")
result = "abcde".translate(table)
print(result)  # "123de"

2. 문자 삭제만 수행

# 'aeiou' 제거
table = str.maketrans("", "", "aeiou")
result = "hello world".translate(table)
print(result)  # "hll wrld"

3. 직접 딕셔너리로 매핑 테이블 정의

# 유니코드 기반 변환 규칙 정의
table = {ord('x'): '1', ord('y'): '2', ord('z'): None}  # 'x'->'1', 'y'->'2', 'z' 삭제
result = "xyzabc".translate(table)
print(result)  # "12abc"

4. 변환과 삭제 혼합 사용

table = str.maketrans("abc", "123", "xyz")  # 'a'->'1', 'b'->'2', 'c'->'3', 'xyz' 삭제
result = "xyzyyzaxbyycxyzz".translate(table)
print(result)  # "123"

5. 구두점 제거

# maketrans()로 테이블 만들기
table = str.maketrans('', '', string.punctuation)
# translate()로 구두점 제거
paragraph = paragraph.translate(table)

6. 구두점을 공백으로 변환

# maketrans()로 테이블 만들기
table = str.maketrans(string.punctuation, ' ' * len(string.punctuation))
# translate()로 구두점 제거
paragraph = paragraph.translate(table)

장점

- 여러 개의 문자를 매핑 테이블로 간결하게 변환 및 삭제 가능.

- 메서드가 C로 구현되어 있어 속도가 빠름.

단점

- 단순히 문자 단위로 변환하고 삭제하는 것이기에, 복잡한 패턴 매칭을 해결하기에는 어려울 수 있음. -> `re.sub()` 사용

- x랑 y 길이가 꼭 같아야 하므로 사용하기 좀 까다로울 수 있음.

- 'table'와 같은 변수를 메모리에 정의하는 것이므로, 대규모 매핑 테이블 생성 시 메모리 부담이 될 수 있음.


3. re.sub()

****잠깐!! 이 파트를 읽기 전에, 해당 글을 먼저 읽고 오자. 

https://wikidocs.net/1669

 

08장 정규표현식

필자는 ‘정규 표현식’을 이 책에 다뤄야 할지 오랫동안 고민했다. 정규 표현식은 꽤 오랜 기간 코드를 작성해 온 개발자라도 잘 모를 수 있는 고급 주제여서 초보자를 대상으로 하는…

wikidocs.net

주어진 정규 표현식 패턴을 사용해 문자열에서 일치하는 부분을 찾아 새로운 문자열로 대체하는 함수.

문법

re.sub(pattern, repl, string, count=0, flags=0)

매개변수

1. pattern (필수)

- 정규 표현식 패턴. 

- 문자열에서 이 패턴과 일치하는 모든 부분을 찾음.

2. repl (필수)

- 찾은 패턴을 대체할 문자열. 또는 교체 작업을 수행할 함수.

- 정규 표현식에서 매칭된 부분을 해당 조건에 따라 치환.

3. string (필수)

- 패턴을 찾고자 하는 내 원본 문자열.

4. count (선택, default = 0)

- 교체를 수행할 최대 횟수.

- 본값은 0으로, 패턴이 매칭된 모든 부분을 교체.

5. flags (선택, default = 0)

- 정규 표현식의 동작 방식을 제어하는 플래그.

- 대소문자 구분 여부(re.IGNORECASE), 멀티라인 처리(re.MULTILINE) 등을 설정할 수 있음.

- 여러 플래그를 `|`로 결합 가능.

반환값

- 치환 작업이 완료된 새로운 문자열을 반환.

예제

1. 단순 패턴 치환

import re
text = "abc123def456"
result = re.sub(r"\d+", "X", text)
print(result)  # "abcXdefX"

2. repl에 치환 람다 함수 사용

import re
text = "abc123def456"
result = re.sub(r"\d+", lambda m: str(int(m.group(0)) * 2), text)
print(result)  # "abc246def912"

3. 대소문자 구분 제거 플래그 사용

import re
text = "Apple apple APPLE"
result = re.sub(r"apple", "fruit", text, flags=re.IGNORECASE)
print(result)  # "fruit fruit fruit"

 

4. 구두점을 공백으로 변환

# 정규 표현식 사용
paragraph = re.sub(r'[^\w]', ' ', paragraph

# 단어 문자(\w)가 아닌 모든 문자를 매칭해서,
# 그걸 공백으로 교체함.

# '단어 문자'란, 알파벳, 숫자, 밑줄(_)을 의미.
# r''은 원시 문자열을 나타내, 이스케이프 문자가 그대로 문자로 처리되도록 해줌.
# ^는 부정을 나타냄.

장점

- 매우 강력한 패턴 매칭과 치환 작업을 지원함.

- 정규 표현식의 모든 기능을 활용 가능해 매우 유연함.

단점

- 정규 표현식 문법을 결국 공부하고 써야 하기 때문에, 학습 곡선이 있고 난이도가 있음.

- 단순한 문자열 치환에는 그냥 `str.replace()`를 쓰는 게 더 효율적.

- `re` 모듈에 파이썬 코드로 구현되어있는 것이기 때문에, 나머지 두 메서드에 비해 비교적 느림.


성능 비교

https://docs.python.org/ko/3/howto/regex.html#use-string-methods

https://stackoverflow.com/questions/265960/best-way-to-strip-punctuation-from-a-string

https://stackoverflow.com/questions/56378872/replace-multiple-special-characters-most-efficient-way

위 글 포함 글 맨 아래 첨부한 여러 Ref.들을 참고한 결과, 다음과 같은 추세가 있다고 정리해볼 수 있음.

 

1. 단순한 문자열 교체에서는,

- `re.sub()`보다 `str.replace()`를 쓰는 것이 더 빠르다.

- `str.translate()`는 다들 알다시피 문자열 교체가 아닌 여러 문자 교체로, 문자열 교체에 사용하기엔 제한적이다.

- 따라서, 일반적으로 `str.replace` [ < `str.translate()`] < `re.sub()` 순으로 오래 걸린다.

- 그러나, 이 경우 어떻게 로직을 짜느냐에 따라 실행 시간이 많이 차이날 수 있어서, 

- 위 우위 관계를 맹신하지 말고, 그냥 필요한 기능에 따라 적절하게 수행하는 것이 더 나아보인다.

2. 다양한 여러 문자들을 교체 또는 삭제할때는,

- `re.sub()`보다 `str.translate()`를 쓰는 것이 더 빠르다.

- `str.replace()`를 쓰게 되면 여러 번 반복해서 호출해야 하기에, `str.translate()` 또는 `re.sub()`를 써서 한 번만 호출하는 것이 더 빠르다.

- 따라서, 일반적으로 `str.translate()` < `re.sub()` < `str.replace()` 순으로 오래 걸린다.

- 이는 아래 두 링크의 `Olvin Roght`씨와 `yatu` 씨의 답변에 잘 정리되어 있다.(time test 결과 또한 나와있음)

https://stackoverflow.com/a/56379160

순서대로 replace, translate, sub

https://stackoverflow.com/a/266162

순서대로 sub, translate, replace

4. 즉, 일반적으로는 `re.sub()`보다 `문자열 메서드`들을 쓰는 것이 다 빠르다.

3. 그럼에도 불구하고, 복잡한 패턴 매칭이 필요할 땐 결국 `re.sub()`를 쓸 수밖에 없다.

 


Ref.

더보기

https://docs.python.org/ko/3/howto/regex.html#use-string-methods

 

Regular Expression HOWTO

Author, A.M. Kuchling < amk@amk.ca>,. Abstract: This document is an introductory tutorial to using regular expressions in Python with the re module. It provides a gentler introduction than the corr...

docs.python.org

 

https://stackoverflow.com/questions/56378522/str-translate-vs-str-replace-when-to-use-which-one

 

str.translate vs str.replace - When to use which one?

When and why to use the former instead of the latter and vice versa? It is not entirely clear why some use the former and why some use the latter.

stackoverflow.com

 

https://dev.to/doridoro/python-differences-between-replace-and-resub-methods-1cfj

 

Python: differences between `.replace()` and `.re.sub()` methods

Introduction The .replace() method and the .re.sub() function in Python are both used for...

dev.to

 

https://note.nkmk.me/en/python-str-replace-translate-re-sub/#replace-different-substrings

 

Replace strings in Python (replace, translate, re.sub, re.subn) | note.nkmk.me

In Python, you can replace strings using the replace() and translate() methods, or the regular expression functions, re.sub() and re.subn(). You can also replace substrings at specified positions usin ...

note.nkmk.me

 

https://seong6496.tistory.com/414

 

[파이썬] 여러문자 한번에 치환하기

여러문자 한꺼번에 치환하기 파이썬에서 문자열을 다루다보면 특정 문자열을 한꺼번에 다른 문자열로 치환해야 하는 경우가 있습니다. 이번에는 파이썬에서 여러 문자열을 한꺼번에 치환해주

seong6496.tistory.com

 

https://dogsavestheworld.tistory.com/entry/python-%EB%AC%B8%EC%9E%90%EC%97%B4-%EC%B9%98%ED%99%98-%EC%B4%9D-%EC%A0%95%EB%A6%AC-%EB%B0%8F-%EC%84%B1%EB%8A%A5-%EB%B9%84%EA%B5%90%ED%95%98%EA%B8%B0strtranslate-strreplace-resub#str.translate,_str.replace,_re.sub_%EC%84%B1%EB%8A%A5_%EB%B9%84%EA%B5%90

 

[python] 문자열 치환 총 정리 및 성능 비교하기(str.translate, str.replace, re.sub)

목차 Intro 데이터 전처리 과정은 분석 결과/ 모델 성능에 중요한 영향을 미치기에, 데이터 전처리 과정에서 데이터 정제에 속하는 문자열을 치환하는 방법을 제대로 이해하고자 합니다. 파이썬

dogsavestheworld.tistory.com

 

https://blog.naver.com/jaeyoon_95/222668030072

 

파이썬 translate 사용법

파이썬을 사용하다보면, 문자열 내에 특정 문자를 다른 문자로 변환하는 경우가 생깁니다. 이럴때는 보통 ...

blog.naver.com

 

https://stackoverflow.com/questions/56378872/replace-multiple-special-characters-most-efficient-way

 

Replace multiple (special) characters - most efficient way?

At the texts that I have, I want to replace the following special characters with a single space: symbols = ["`", "~", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "-", "+", "=", "{"...

stackoverflow.com

 

https://stackoverflow.com/questions/265960/best-way-to-strip-punctuation-from-a-string

 

Best way to strip punctuation from a string

It seems like there should be a simpler way than: import string s = "string. With. Punctuation?" # Sample string out = s.translate(string.maketrans("",""), string.punctuation) Is there?

stackoverflow.com