< 문자열 분리 >
> 첨자
파이썬은 문자열을 기본 타입으로 지원할 뿐만 아니라 문자열을 조작하는 풍부한 명령을 제공한다.
문자열은 메모리상에 개별 문자들이 일렬로 쭉 늘어선 형태로 저장된다.
문자열을 구성하는 개별 문자를 읽을 때는 [ ] 괄호와 문자의 위치인 첨자를 적는다.
첨자는 앞에서 셀수도 있고 뒤에서 셀 수도 있다.
0 | 1 | 2 | 3 | 4 | 5 |
p | y | t | h | o | n |
-6 | -5 | -4 | -3 | -2 | -1 |
앞에서 셀 때는 0 부터 시작하여 첫 문자가 [0]번 이며 뒤로 갈 수록 1 씩 증가한다.
뒤에서 셀 때는 음수를 사용하여 제일 마지막 문자가 [-1]번 이며 앞으로 갈수록 1 씩 감소한다.
# index
s = "python"
print(s[2])
print(s[-2])
t
o
* 첨자는 반드시 문자열의 길이 범위 안이어야 한다.
# string index
s = "python"
for c in s:
print(c, end=',')
p,y,t,h,o,n,
* s 문자열을 구성하는 문자를 c 변수로 하나씩 읽어 콤마로 구분하여 출력
for i in range(len(s)):
print(s[i], end=',')
* 제어 변수 i 를 0 에서 시작하여 len(s) 직전까지 돌며 s[i] 를 읽으면 첫 문자부터 끝까지 순서대로 모든 문자를 순회한다.
파이썬의 문자열은 변경 불가능한(Immutable) 자료형이어서 한번 초기화되면 바꿀 수 없다.
[ ] 로는 개별 문자를 읽을 수만 있으며 다른 문자를 대입하거나 삽입, 삭제할 수는 없다.
다음 코드는 될 것 같지만 대입할 수 없다는 에러가 발생한다.
s = "python"
s[2] = "k" # Error
* 한번 초기화한 문자열을 변경할 수 없도록 한 이유는 편집을 금지하면 메모리를 훨씬 더 절약하고 속도도 빨라지기 때문이다.
> 슬라이스
[ ] 괄호 안에 첨자를 하나만 적으면 해당 위치의 문자를 읽지만 범위를 지정하면 부붐 문자열을 추출한다.
[ ] 괄호 안에 시작, 끝 증가값을 지정하는데 range 함수와 구조가 같다.
[begin:end:step]
* 범위의 원칙에 의해 시작 위치는 포함되지만 끝 위치는 포함되지 않아 끝 위치 직전의 문자까지만 추출된다.
시작 위치를 생략하면 0 이 적용되어 문자열의 처음부터 추출하며 끝 위치를 생략하면 문자열의 끝까지 추출한다.
# slice
s = "python"
print(s[2:5]) #tho
print(s[3:]) #hon
print(s[:4]) #pyth
print(s[2:-2]) #th
* 슬라이스 기능을 잘 활용하면 일정한 형식을 가진 문자열에서 원하는 정보만 쏙 뽑아낼 수 있다.
# slice_2
file = "20171224-104830.jpg"
print("촬영날짜: " + file[4:6] + "월" + file[6:8] + "일") # 촬영날짜: 12월24일
print("촬영시간: " + file[9:11] + "시" + file[11:13] + "분") # 촬영시간: 10시48분
print("확장자: " + file[-3:]) # 확장자: jpg
* 디지털 카메라의 파일명에는 촬영 날짜와 시간 등의 정보가 기록되어 있다.
범위의 마지막 값인 step 은 건너뛸 문자 수를 지정하는데 생략 시 1 을 적용하여 모든 문자를 차례대로 읽는다.
step 을 2로 지정하면 두칸씩 점프하여 한 문자씩 건너 뛰며 읽는다.
-1 을 지정하면 문자열을 거꾸로 읽기도 한다.
# slice_3
yoil = "월화수목금토일"
print(yoil[::2]) # 월수금일
print(yoil[::-1]) # 일토금목수화월
< 문자열 메서드 >
> 검색
문자열은 수치형에 비해 복잡하고 길이도 가변적이어서 연산자로 자유자재로 조작하기 어렵다.
그래서 문자열을 관리하는 여러 가지 복잡한 함수가 제공된다.
# find
s = "python programming"
print(len(s)) # 18
print(s.find('o')) # 4
print(s.rfind('o')) # 9
print(s.index('r')) # 8
print(s.count('n')) # 2
*
len 함수는 문자열의 길이를 조사하는데 인수로 문자열을 전달하면 문자의 개수를 리턴한다.
내장 함수(Built in)여서 문자열 뿐만 아니라 리스트나 튜플 같은 다른 컬렉션에서도 사용할 수 있으며 요소의 개수를 조사한다.
메서드는 클래스에 소속되어 있는 함수이며 객체에 대해 특화된 작업을 수행한다.
객체.메서드( ) 식으로 대상 객체가 메서드를 호출한다.
내장 함수와 객체 소속의 메서드는 호출 방식이 다르다는 점을 유의하자.
len 함수는 내장이어서 s.len( )이 아닌 len(s)로 호출한다.
len(s) # 내장 함수
s.find('o') # 메서드
find 메서드는 인수로 지정한 문자 또는 부분 문자열의 위치를 조사한다.
rfind 메서드의 r은 rear의 약자이며 뒤에서 검색을 시작한다.
똑같은 문자 'o' 를 찾아도 앞에서부터 찾을 때와 뒤에서부터 찾을 때의 검색 결과가 다르다.
대상 문자가 없을 경우 두 함수 모두 -1 을 리턴한다.
index 메서드도 문자를 찾는다면 면에서 기능은 같지만 해당 문자가 없을 때 예외가 발생한다는 점이 다르다.
반드시 예외 처리 구문으로 감싸야 한다는 면에서 find 보다는 쓰기 까다롭다. (Error 발생)
rindex 함수는 뒤에서부터 검색한다.
count 메서드는 특정 문자의 개수를 센다.
해당 문자나 문자열이 발견되지 않으면 0 을 리턴한다.
# count
s = """생각이란 생각할수록 생각나므로 생각하지 말아야 할 생각은
생각하지 않으려고 하는 생각이 옳은 생각이라고 생각합니다."""
print("생각의 출현 횟수: ", s.count('생각'))
생각의 출현 횟수: 9
* 문자 뿐만 아니라 count('sub') 식으로 부분 문자열도 검색할 수 있다.
find 는 어디에 있는지 첫 번째 발견 위치만 찾는 데 비해 count 는 몇개나 있는지 전체 문자열을 다 조사한다.
똑같은 검색 동작을 하지만 조사하는 정보가 조금씩 달라 상황에 맞는 함수를 잘 선택해야 한다.
> 조사
특정 문자가 어디에 있는지는 관심이 없고 단순히 있는지 없는지만 알고 싶을 때는 in 구문을 사용한다.
함수가 아닌 키워드여서 "단어 in 문자열" 형식으로 사용한다.
포함되어 있으면 True 를 리턴하고 그렇지 않으면 False 를 리턴한다.
반대로 not in 은 포함되어 있지 않은지 조사한다.
# in
s = "python programming"
print("a" in s) # True
print("z" in s) # False
print("pro" in s) # True
print("x" not in s) # True
* in, not in 구문은 문자열 뿐만 아니라 이후에 알아볼 리스트, 튜플, 사전 등의 컬렉션에 공통적으로 적용된다.
startswith 메서드는 특정 문자열로 조사되는지 조사한다.
문자열 전체나 중간이 아닌 앞부분의 일부만 비교한다는 점에서 find 나 index와 다르다.
반대로 endswith 메서드는 특정 문자열로 끝나는지 뒷부분만 비교한다.
# startswith
name = "김한결"
if name.startswith("김"):
print("김가입니다.")
if name.startswith("한"):
print("한가입니다.")
file = "girl.jpg"
if file.endswith(".jpg"):
print("그림 파일입니다.")
김가입니다.
그림 파일입니다.
find 나 count 는 해당 문자열이 중간에 있어도 검색해 내지만 startswith 는 앞부분에 있는지 문자열만 검색한다.
파일의 종류를 판별할 때는 뒷 부분이 특정 확장자인지 점검해 보면 되니 endswith 함수가 적합하다.
사용자로부터 수치값을 입력받아야 한다고 해 보자.
이때 반드시 0 ~ 9 까지의 아라비아숫자만 입력해야 하는데 실수로 엉뚱한 값을 입력할 수도 있다.
사용자가 제대로 입력했는지 조사할 때 isdecimal 함수로 모두 숫자가 맞는지 조사한다.
# isdecimal
height = input("키를 입력하세요 :")
if height.isdecimal():
print("키 =", height)
else:
print("숫자만 입력하세요.")
* isdecimal 이 True 를 리턴한다면 이 문자열은 int 함수로 전달하여 정수로 안전하게 바꿀 수 있다.
> 변경
lower 메서드는 영문자를 전부 소문자로 바꾸며
upper 메서드는 반대로 전부 대문자로 바꾼다.
swapcase는 대소문자를 반대로 뒤집는다.
capitalize 는 문장의 첫 글자만 대문자로 바꾸고
title 은 모든 단어의 처음을 대문자로 바꾼다.
제품키나 에러 코드 등은 대소문자를 엄격히 구분하므로 원하는 형식으로 바꾼 후 저장, 비교해야 한다.
# lower
s = "Good morning. my love KIM."
print(s.lower())
print(s.upper())
print(s)
print(s.swapcase())
print(s.capitalize())
print(s.title())
good morning. my love kim.
GOOD MORNING. MY LOVE KIM.
Good morning. my love KIM.
gOOD MORNING. MY LOVE kim.
Good morning. my love kim.
Good Morning. My Love Kim.
* 파이썬의 문자열은 한번 초기화되면 이후에는 바뀌지 않는 특성이 있다.
lower 는 모두 소문자로 바꾼 새로운 문자열로 리턴할 뿐 문자열 자체를 변경하지 않는다.
lower 와 upper 를 호출한 후에도 s는 여전히 원래 값을 유지한다.
만약 s의 모든 문자를 소문자로 바꾸고 싶다면 lower가 리턴하는 값을 s에 다시 대입한다.
s = s.lower()
이렇게 하면 s문자열 자체가 바뀐다.
# str lower
python = input("파이썬의 영문 철자를 입력하시오: ")
if python.lower() == "python":
print("맞췄습니다.")
* 소문자로 바꾼 문자열을 출력한다면 굳이 대입할 필요가 없다.
사용자가 입력한 문자열을 대소문자 상관 없이 소문자로 바꾼 후 "python" 문자열과 비교
사용자로부터 문자열을 입력받거나 다른 문자열에서 분리해 내면 앞 뒤로 불필요한 공백이 들어가는 경우가 빈번하다.
공백은 눈에 보이지 않지만 쓸데 없이 공간을 차지하며 id나 코드값처럼 정확한 값을 비교할 때 엉뚱한 결과가 나오기도 한다.
의미 없는 공백을 제거할 때는 다음 메서드를 사용한다.
# strip
s = " angel "
print(s + "님")
print(s.lstrip() + "님")
print(s.rstrip() + "님")
print(s.strip() + "님")
angel 님
angel 님
angel님
angel님
* lstrip 은 왼쪽공백만, rstrip 은 오른쪽 공백만, strip 은 양쪽의 공백 모두 제거한다.
DB에 기록하거나 네트워크로 전송할 문자열은 앞 뒤의 공백을 깔끔하게 정리한 후 사용해야 한다.그렇지 않으면 기억장소를 낭비할 뿐만 아니라 차후 여러가지 문제를 일으킨다.
> 분할
split 메서드는 구분자를 기준으로 문자열을 분할한다.
하나의 문자열이 여러 개의 부분 문자열로 쪼개져 리스트에 저장된다.
이 리스트로부터 개별 문자열을 하나씩 빼내 사용한다.
# split
s = "짜장 짬뽕 탕슉"
print(s.split()) # 인수없이 그냥 호출하면 공백을 기준으로 문자열 분할
s2 = "서울->대전->대구->부산"
city = s2.split("->") # 인수로 구분 문자열을 주면 해당 문자열을 기준으로 분할
print(city)
for c in city:
print(c, "찍고", end=" ")
['짜장', '짬뽕', '탕슉']
['서울', '대전', '대구', '부산']
서울 찍고 대전 찍고 대구 찍고 부산 찍고
* 인수 없이 그냥 호출하면 공백을 기준으로 문자열을 분할한다.
즉, 디폴트 구분자는 공백이어서 문자열을 구성하는 단어를 분할한다.
인수로 구분 문자열을 주면 해당 문자열을 기준으로 분할한다.
splitlines 메서드는 개행 문자나 파일 구분자, 그룹 구분자 등을 기준으로 문자열을 잘라 리스트를 만든다.주로 개행 코드를 기준으로 한 행씩 잘라내며 긴 문서를 각 행별로 쪼개 관리 할 때 편하다.
# split lines
traveler = """강나루 건너서 \n 밑발 길을 \n\n구름에 달 가듯이\n가는 나그네\n
길은 외줄기\n남도 삼백리\n\n술 익는 마을마다\n타는 저녁놀\n
구름에 달 가듯이\n가는 나그네"""
poet = traveler.splitlines()
for line in poet:
print(line)
강나루 건너서
밑발 길을
구름에 달 가듯이
가는 나그네
길은 외줄기
남도 삼백리
술 익는 마을마다
타는 저녁놀
구름에 달 가듯이
가는 나그네
* 그냥 출력해도 결과는 같지만 행별로 나누어 놓으면 각 행에 대해 개별적인 처리가 가능하다.
예를 들어 행별로 번호를 붙인다거나 정렬을 다르게 지정할 수 있다.
split 메서드와 반대로 join 메서드는 문자열의 각 문자 사이에 다른 문자열을 끼워 넣는다.
# join
s = "._."
print(s.join("대한민국")) # 대._.한._.민._.국
# split join
s2 = "서울->대전->대구->부산"
city = s2.split("->")
print(" 찍고 ".join(city)) # 서울 찍고 대전 찍고 대구 찍고 부산
* join 메서드는 문자열 요소를 가지는 리스트에 대해서도 사용할 수 있다.
split 메서드로 문자열을 분할하고 join 메서드로 다시 합치되 중간 중간에 "찍고" 문자열을 삽입
> 대체
replace 메서드는 특정 문자열을 찾아 다른 문자열로 바꾼다.
첫 번째 인수로 검색할 문자열을 지정하고,
두 번째 인수로 바꿀 문자열을 지정한다.
# replace
s = "독도는 일본땅이다. 대마도도 일본땅이다."
print(s) # 독도는 일본땅이다. 대마도도 일본땅이다.
print(s.replace("일본", "한국")) # 독도는 한국땅이다. 대마도도 한국땅이다.
* 필요하다면 세 번째 인수로 바꿀 개수를 지정하여 앞쪽의 일부만 교체할 수도 있다.
문자열을 일괄 변경할 때 효율적이며 정규 표현식을 사용하면 더 정밀한 검색과 대체도 가능하다.
다음 함수들은 문자열을 특정 폭에 맞추어 정렬한다.
정렬이란 공백을 어디다 둘 것인가를 결정하는 것인데 좌, 우, 중앙으로 정렬할 수 있다.
인수로 정렬할 폭을 지정한다.
# just
message = "안녕하세요"
print(message.ljust(30))
print(message.rjust(30))
print(message.center(30))
안녕하세요
안녕하세요
안녕하세요
문자열을 메서드의 간단한 사용방법을 살펴봤는데 생략 가능한 인수까지 다 활용하면 더 섬세하게 조작할 수 있다.
< 포맷팅 >
> 포맷팅
문자열 안에 여러 가지 세부 정보를 포함하여 출력할 때는 + 연산자로 연결한다.
문자열에 + 연산자를 연거푸 사용하면 뒤에 정보를 계속 추가하여 얼마든지 많이 연결할 수 있다.
다음 예제는 문자열 중간에 price 변수의 값을 집어 넣어 출력한다.
# string cat
price = 500
print("궁금하면 " + str(price) + "원!")
궁금하면 500원!
* 잘 동작하지만 + 연산자를 여러번 사용해야 한다는 점과
문자열이 아닌 값은 연결하기 전에 str 함수로 일일이 문자열로 변환해야 한다는 점이 불편하다.
중간에 삽입될 값이 여러 개이면 식이 너무 복잡하고 길어져 편집하기도 어렵다.
다음과 같이 개별 변수를 출력할 수도 있다.
print("궁금하면 ", price, "원!")
print 함수가 가변 인수를 받기 때문에 콤마로 구분하여 임의의 값을 넘기기만 하면 된다.
그러나 이 방법은 정보 사이에 공백이 들어가고 출력만 할 뿐 하나의 문자열을 만들어 내는 것은 아니다.
포맷팅은 문자열 사이사이에 다른 정보를 삽입하여 조립하는 기법이다.
표 식 | 설 명 |
%d | 정수 |
%f | 실수 |
%s | 문자열 |
%c | 문자 하나 |
%h | 16진수 |
%o | 8진수 |
%% | % 문자 |
# format
price = 500
print("궁금하면 %d원!" % price) # 궁금하면 500원!
# format_2
month = 8
day = 15
anni = "광복절"
print("%d월 %d일은 %s이다." % (month, day, anni)) # 8월 15일은 광복절이다.
일정한 폭을 강제로 할당하여 출력하면 변수의 값에 상관없이 숫자의 자리수를 가지런히 맞출 수 있어 보기 좋고 숫자 파악이 쉽다.
# align
price = [30, 13500, 2000]
for p in price:
print("가격:%d원" % p)
for p in price:
print("가격%7d원" % p)
가격:30원
가격:13500원
가격:2000원
가격 30원
가격 13500원
가격 2000원
* 폭을 지정하지 않고 %d 서식을 사용하면 가격의 자리수에 따라 숫자가 들쭉날쭉해 대소 관계를 한눈에 파악하기 어렵지만,
%7d 서식으로 7자리를 강제 지정하면 오른쪽 끝이 가지런해서 숫자를 한눈에 파악할 수 있다.
'Language > Python' 카테고리의 다른 글
Python_10. Dictionary and Set (0) | 2022.08.01 |
---|---|
Python_09. List and Tuple (0) | 2022.08.01 |
Python_07. Function (0) | 2022.07.31 |
Python_06. Iteration (0) | 2022.07.27 |
Python_05. Conditional Statement (0) | 2022.07.27 |