https://cuffyluv.tistory.com/120
- 해당 문자열 치환 문제를 풀고 정리하면서, 같은 문제를 `str.replace`, `re.sub`, `str.translate` 세 함수 및 메서드 모두로 풀 수 있음을 확인하였다.
- 따라서, 저 세 함수 및 메서드 각각을 어떤 상황에 사용해야 할지 그 특성과 장단점 및 성능을 비교해 정리해보고자 한다.
- str.replace()
- str.translate()
- 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()
****잠깐!! 이 파트를 읽기 전에, 해당 글을 먼저 읽고 오자.
주어진 정규 표현식 패턴을 사용해 문자열에서 일치하는 부분을 찾아 새로운 문자열로 대체하는 함수.
문법
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
https://stackoverflow.com/a/266162
4. 즉, 일반적으로는 `re.sub()`보다 `문자열 메서드`들을 쓰는 것이 다 빠르다.
3. 그럼에도 불구하고, 복잡한 패턴 매칭이 필요할 땐 결국 `re.sub()`를 쓸 수밖에 없다.
Ref.
https://docs.python.org/ko/3/howto/regex.html#use-string-methods
https://stackoverflow.com/questions/56378522/str-translate-vs-str-replace-when-to-use-which-one
https://dev.to/doridoro/python-differences-between-replace-and-resub-methods-1cfj
https://note.nkmk.me/en/python-str-replace-translate-re-sub/#replace-different-substrings
https://seong6496.tistory.com/414
https://blog.naver.com/jaeyoon_95/222668030072
https://stackoverflow.com/questions/56378872/replace-multiple-special-characters-most-efficient-way
https://stackoverflow.com/questions/265960/best-way-to-strip-punctuation-from-a-string
'Programming > Python' 카테고리의 다른 글
[Python] sorted() 함수와 list.sort() 메서드 설명 및 비교. (0) | 2025.01.29 |
---|---|
[Python] import문 사용법(패키지, 모듈 차이) (0) | 2024.08.17 |