파이썬은 문자열을 다룰때 다양한 형태로 문자열을 다룰 수 있습니다. C나 Java같은 언어에서는 문자열을 쌍따옴표로 둘러싸서 문자열을 표현하지만 파이썬은 ', ", ''' 로 둘러싸서 문자열을 표현할 수 있죠. 이렇게하는 이유는 ', " 가 문자열에 글자로 표현될 때 문자열의 종료나 시작으로 인식하지 않게 하기 위함입니다.

str1 = 'python'
str2 = "python"
str3 = '''python'''

print (str1, str2, str3)

str1 = '"python"'
str2 = "'python'"
str3 = '''"python"'''

print ( str1, str2, str3)
python python python
"python" 'python' "python"

 

이제부터 파이썬의 문자열에 대해서 알아보도록 하겠습니다. 

문자열 포맷

- 포맷 문자를 통한 문자열 포맷

C와 같이 문자열에 다른 데이터를 포함시키려면 format 문자를 사용해서 정수든, 글자든 입력받을 수가 있죠.

포맷 문자 설명
%d 10진수 정수 (Decimal)
%c 문자 (Character)
%f 부동 소수 (Floating Point)
%o 8진수 정수 (Octal)
%x 16진수 정수 (Hexadecimal)
%s 문자열 (String)
%% % 문자

 

C에서 지원하는 무자열 형태의 format은 거의다 지원한다고 보시면됩니다. 그렇기 때문에 아래의 링크를 통해서 더 많은 문자열 포맷을 활용하는 방법을 알아보시기 바랍니다.

reakwon.tistory.com/169

 

[C언어] 출력 형식(format) 총정리 (Feat. sprintf, fprintf) - 일정한 간격으로 문자열 출력 예제 까지

C언어의 다양한 출력 문자들 C언어에서 다양한 출력 형식을 지원합니다. 우리가 너무나 잘 알고 있는 부호있는 정수형은 %d, 문자열 출력은 %s 등이 그 출력형식인데요. 오늘은 자세하게 한번 총

reakwon.tistory.com

 

형식을 지정할 데이터는 문자열 끝 %를 이용해서 나열해줍니다.

print ('구구단 2단')
for i in range(10):
    print ('%d * %d = %d' % (2, i, 2*i) )
구구단 2단
2 * 0 = 0
2 * 1 = 2
2 * 2 = 4
2 * 3 = 6
2 * 4 = 8
2 * 5 = 10
2 * 6 = 12
2 * 7 = 14
2 * 8 = 16
2 * 9 = 18

 

- format함수를 통한 문자열 포맷

이와 같은 방식은 우선 자료형에 따른 포맷 문자를 알고있어야하는 단점이 있습니다. 파이썬 3부터는 포맷을 알고 있지 않아도 사용할 수 있는 방법은 format함수를 사용할 수 있습니다. 여기서 중괄호를 이용합니다. 숫자를 입력하여 차례대로 입력받을 수도 있고, 명시적으로 이름을 지정해서 사용할 수도 있습니다.

str = 'str.{} example'.format('format')
print(str)
                                                #  {0}      {1}        {2}          {3}
str = 'SELECT {0} FROM {1} WHERE {2} = {3}'.format('*', 'accounts', 'email', 'reakwon@gmail.com')
print (str)

str = 'name : {name}, age : {age}'.format(name='kim',age=22)
print (str)
str.format example
SELECT * FROM accounts WHERE email = reakwon@gmail.com
name : kim, age : 22

 

- f String을 사용한 문자열 포맷

문자열을 저장할때 가장 맨 앞에 f를 준 후 변수명을 그대로 문자열에 중괄호로 입력하면 그 변수명의 데이터가 그대로 문자열에 입력됩니다. f는 format의 약자라는 점은 참고해주세요. 이 f string은 파이썬 3.6부터 지원합니다.

name = 'shin'
age = 22
score = 80

result = f'name : {name}, age : {age}, score : {score}'
print (result)
name : shin, age : 22, score : 80

 

산술 연산도 할 수 있습니다.

a = 10
b = 20

fstr = f'{a} * {b} = {a*b}, {a} + {b} = {a+b}'
print (fstr)
10 * 20 = 200, 10 + 20 = 30

 

함수의 반환값도 쓸수 있죠.

def mult(a, b):
    return a*b

def add(a, b):
    return a+b

a = 5
b = 9
fstr = f'{a} * {b} = {mult(a,b)}, {a} + {b} = {add(a,b)}'
print (fstr)
5 * 9 = 45, 5 + 9 = 14

 

문자열 메소드

문자열 메소드는 엄청 많은데, 그 중에서 몇가지 문자열 메소드를 알아보도록 하겠습니다. 문자열은 아래의 문자열을 사용해보지요.

paul_rand = 'Do not to be original, just-try-to-be-good.'

 

- 문자열 길이 : len

문자열 내장 메소드는 아니지만 길이를 알고자 하는 경우 len 내장 함수를 쓰면 됩니다.

print(len(paul_rand))
43

 

- 문자수 세기 : count

문자나 문자열의 수를 새려면 count 메소드를 사용하여 확인할 수 있습니다.

print (paul_rand.count('t'))        #t문자 세기
print (paul_rand.count('to'))      #to 문자열 세기
5
2

 

- 대소문자로 변경 : upper, lower, casefold

알파벳을 모두 소문자로 변경하려면 lower 메소드 사용하면 되는데 소문자로 변경하는 메소드는 casefold라는 메소드도 있습니다. 반대로 모두 대문자로 변경하려면 upper를 사용하면 됩니다.

print (paul_rand.upper())   #모두 대문자로 변경
print (paul_rand.lower())   #모두 소문자로 변경
print (paul_rand.casefold())
DO NOT TO BE ORIGINAL, JUST-TRY-TO-BE-GOOD.
do not to be original, just-try-to-be-good.
do not to be original, just-try-to-be-good.

 

- 문자열 분리 : split

문자열을 공백, 또는 지정된 나누려고 구분된 구분자에 따라서 문자열을 쪼개고 싶다면 split 메소드를 사용할 수 있습니다. 인자를 넣어주지 않는다면 공백을 기준으로 나누고, 지정한 문자열을 넘겨주면 그 문자열을 기준으로 문자열을 나눕니다. 쪼개어진 문자열들은 리스트 형태로 넘겨줍니다.

tokens = paul_rand.split()
print (tokens)

tokens = paul_rand.split('-')
print (tokens)
['Do', 'not', 'to', 'be', 'original,', 'just-try-to-be-good.']
['Do not to be original, just', 'try', 'to', 'be', 'good.']

 

- 문자열 공백 지우기 : strip, lstrip, rstrip

문자열에 공백을 제거하려면 strip 메소드를 사용하면 됩니다. 특별히 왼쪽 공백은 lstrip, 오른쪽 공백은 rstrip을 사용하면 됩니다.

str = '  __name__  __main__    '

print (str.lstrip())    # 왼쪽 공백 제거
print (str.rstrip())    # 오른쪽 공백 제거
print (str.strip())     # 양쪽 공백 제거
__name__  __main__    
  __name__  __main__
__name__  __main__

 

- 문자열 위치 : find, index, rfind, rindex

문자열에서 특정 문자열이 어느 위치에 있는지 확인하려면 find와 index를 사용하면 됩니다. 이때 가장 첫번째로 등장한 위치를 반환합니다. find와 index의 차이점은 문자를 찾지 못할때는 에러를 발생시키느냐 마냐입니다. find는 못찾으면 -1을 반환하고 index는 에러를 발생시킵니다.

print ('o : ', paul_rand.find('o'))
print ('. : ', paul_rand.index('.'))
print ('original : ', paul_rand.find('original'))
print ('just : ' ,paul_rand.index('just'))

print ('6 :', paul_rand.find('6'))      #없는 문자열의 경우 -1 반환
print ('6 :', paul_rand.index('6'))     #없는 문자열의 경우 에러

o :  1
. :  42
original :  13
just :  23
6 : -1
Traceback (most recent call last):
  File "C:\Users\grjwu\PycharmProjects\pythonProject1\main.py", line 9, in <module>
    print ('6 :', paul_rand.index('6'))
ValueError: substring not found

 

또는 start와 end 인덱스를 지정하게 되면 그 부분에 대해서만 찾아오게 됩니다.

print (paul_rand.find('to',4,9))    # 글자위치 4부터 9 전까지 탐색
print (paul_rand.index('or',10,19)) # 글자위치 10부터 19 전까지 탐색
7
13

 

왼쪽이 아니라 오른쪽에서 찾아보고 싶다면 rfind와 rindex를 사용하면 됩니다. 이때 결과는 위의 index와 find와 동일하며 오류내는 것도 동일합니다.

good = 'good, good, good~'

print ('o : ', good.rfind('o'))
print ('g : ', good.rindex(','))
o :  14
g :  10

 

 

- 문자열 변경 : replace

특정 문자열을 변경하고 싶다면 replace메소드를 사용하여 바꿀 수 있습니다.

print (paul_rand.replace('to','TO'))
Do not TO be original, just-try-TO-be-good.

 

- 특정 문자열로 시작하느냐 끝나느냐 - startswith, endswith

우리가 지정한 문자열로 시작하느냐를 알아보고 싶다면 startswith, 끝이 나는가를 알아보려면 endswith 메소드를 사용하면 됩니다. 지정된 문자열로 시작, 끝이 나면 True를, 아니면 False를 반환합니다.

print (paul_rand.startswith('Do'))
print (paul_rand.endswith('.'))

print (paul_rand.startswith('The'))
print (paul_rand.endswith('!'))
True
True
False
False

 

- 문자열 삽입 : join

특정 문자열을 문자마다 삽입하고 싶다면 join을 사용하면 됩니다. 글자마다 우리가 지정한 문자열이 삽입되고 만약 단어마다 문자열 삽입을 원한다면 리스트 형태의 문자열 리스트를 전달해주면 됩니다.

 

str = 'ABCDE'
print ("=".join(str))

str = ['Apple','Banana','Cherry']
print (', '.join(str))
A=B=C=D=E
Apple, Banana, Cherry

 

- 탭 간격 조정 : expandtabs

탭의 간격을 조정하는 메소드는 expandtabs입니다. 

str = "h\te\tl\tl"
print (str)
print (str.expandtabs(2))
print (str.expandtabs(4))
print (str.expandtabs(10))
h	e	l	l
h e l l
h   e   l   l
h         e         l         l

 

여기까지 파이썬 문자열의 활용방법과 메소드 들에 대해서 알아보았습니다. 여기서 소개하지 않은 메소드도 많이 있으므로 그때 그때 구글링하여 사용하시기 바랍니다.

반응형
블로그 이미지

REAKWON

와나진짜

,

C언어 문자열 함수

문자열을 다룰때 어떤 문자열 단위로 자르고 싶은 경우나 어떤 문자열에서 임의의 문자열을 찾고 싶은 경우가 있지 않았나요?

그 경우에 사용할 수 있는 문자열 함수를 소개하려고 합니다. 문자열 함수를 사용하기 위해서는 항상 string.h 헤더 파일을 include해야한다는 것을 잊지 마세요.


strtok

이 함수가 문자열을 어떤 문자열 기준으로 자르는 역할을 하는 함수입니다. 일단 함수의 원형을 보시죠.


char *strtok(char *str, const char *delimiters);


2개의 파라미터를 갖고 있죠.


- str : 우리가 어떤 문자열을 자를지 넘겨받는 매개변수입니다.

- delimiters: 구분자라고 합니다. 여기서 자를 기준을 결정하는 것이지요.


예를 들어 str이 "show_me_the_money"라고 합시다. 그리고  문자열을 "_"(구분자)를 기준으로 자른다고 합시다. 그렇다면 show, me, the, money라는 4개의 문자열로 잘리겠죠.


- 반환값 : 잘린 문자열을 반환합니다. 만약 문자열이 전부 끝났다면 NULL을 반환하게 되지요.




이제 함수의 기본적인 설명은 여기까지하고 코드를 보면서 사용법을 확실히 알아보도록 하겠습니다.



strtok source code

#include <stdio.h>
#include <string.h>
int main() {
	
	char str[32] = "show_me_the_money";
	char *tok=strtok(str, "_");

	while (tok != NULL) {
		printf("token : %s\n", tok);
		tok = strtok(NULL, "_");
	}
	printf("기존 문자열 :%s\n", str);
}


우선 결과를 보고 왜 이런 결과가 나왔는지 알아보도록 하지요.


결과


token : show

token : me

token : the

token : money

기존 문자열 :show



이 코드에서는 위의 예와 마찬가지로 "show_me_the_money"라는 문자열을 자르고 있습니다.

strtok는 처음 str 매개변수에 NULL이 아닌 문자열을 사용하면 자를 문자열을 넘겨받은 문자열로 결정합니다.

이후 실행할때 str에 NULL을 전달하면 이전에 설정했던 문자열을 계속해서 자르는 것이죠.


그래서 반복문 while루프 안에서는 strtok에 str인자를 NULL로 넘겨주고 있는 것이죠. 잘 잘려지고 있기는 합니다.


하지만 마지막 줄을 보세요.

마지막 줄은 기존의 문자열 str을 출력하고 있는데 "show_me_the_money"가 출력되지 않고 "show"만 출력이 되고 있습니다. 왜 기존의 문자열인str[32]="show_me_the_money"가 출력이 되지 않는 것일까요?


strtok는 눈치채셨겠지만 자를 문자열을 변환시키면서 문자열을 잘라나갑니다.

우리는 문자열의 마지막 문자가 NULL문자로 끝난다는 것을 알고 있습니다. 그렇다면 마지막에 str이 "show"만을 출력했다는 것은 "show\0"가 된 것을 짐작할 수 있을까요?


"show"이후 문자는 바로 '_' 문자인데, '_'문자가 '\0'인 NULL문자로 바뀌게 된 것 아닐까요?

결론부터 얘기하자면 맞습니다. 우리는 이 한가지만 기억합시다.


문자열의 끝은 모두 '\0'(NULL) 문자로 끝이난다.



이거 하나만 기억하고 strtok가 어떻게 문자열을 자르게 되는지 그 과정을 살펴보도록 합시다.


우선 str이라는 문자열은 다음과 같이 메모리에 잡혀있을 겁니다.





이제 strtok(str,"_")를 호출하는 순간 str에서 "_"라는 문자열이 나올때 그 문자열 자리를 \0로 채우게 됩니다. 그 뒤에 ptr을 반환하게 됩니다. 바로 str[0]의 주소지요.


ptr은 위의 코딩에서 tok가 넘겨받게 되지요. 그래서 tok는 \0까지를 문자열로 인식하게 되므로 처음에는 "show"가 출력되게 되는 것이죠.




이후 ptr을 '\0'다음으로 위치시킵니다. 또 "_"가 나오면 그 자리를 NULL문자로 채우고 ptr의 주소를 반환합니다. 그렇다면 str[5]의 주소가 되겠지요.




이 후 ptr을 str[8]자리로 위치시킵니다. 이 자리는 '\0' 다음 위치지요. 다음에 나오는 "_"를 NULL로 채운 후 ptr을 반환시킵니다.




이제 '\0' 이후에 ptr을 위치시켜 다음 "_"를 찾는데 이제 "_"를 찾을 수 없고 '\0'문자를 만나게 되니까 "money"만을 출력하게 되는 것이죠. 




이 후에는 문자열이 종료되었으므로 strtok는 NULL을 반환하고 while반복문은 종료가 됩니다.


그렇다면 이제 다음 드는 의문은 strtok는 어떻게 ptr의 주소를 기억하고 있을까라는 점입니다. 그런 의문 안드세요?

왜냐면 함수는 종료가 되면 모든 지역변수를 반환하게 되는데 어떻게 ptr이라는 변수는 기억하고 있을까요?

바로 지역변수가 아니기 때문입니다. 변수나 자료형, 메모리 공간을 충분히 알고 있다면 ptr은 정적변수로 선언이 되었다는 것을 눈치챘을 겁니다. 그렇기 때문에 함수가 종료되어도 ptr은 다음 자를 문자열의 주소를 기억하고 있는 겁니다.




제가 한 설명이 의심이 된다면 한번 실험을 해보는 것도 나쁘지 않습니다.

다음의 코드를 실행시켜보세요.


strtok source code2

#include <stdio.h>
#include <string.h>

int main() {

	char str[32] = "show_me_the_money";
	int len = strlen(str);
	int i;
	char *tok;

	for (i = 0; i < len; i++)
		printf("'%c' : str[%d]의 주소:%p\n", str[i], i, &str[i]);
	printf("\n");

	tok = strtok(str, "_");
	while (tok != NULL) {
		printf("token : %s, address:%p\n", tok,tok);
		tok = strtok(NULL, "_");
	}
	printf("\n");

}


만일 제 설명이 맞다면 str을 자른 tok의 주소들이 "_" 이후의 주소들과 같을 겁니다. 왜냐면 "_"이후가 바로 자른 문자열의 시작주소이기 때문이죠.


결과를 보면서 확인해보세요.


결과

token : show, address:008FFC68

token : me, address:008FFC6D

token : the, address:008FFC70

token : money, address:008FFC74


's' : str[0]의 주소:008FFC68

'h' : str[1]의 주소:008FFC69

'o' : str[2]의 주소:008FFC6A

'w' : str[3]의 주소:008FFC6B

' ' : str[4]의 주소:008FFC6C

'm' : str[5]의 주소:008FFC6D

'e' : str[6]의 주소:008FFC6E

' ' : str[7]의 주소:008FFC6F

't' : str[8]의 주소:008FFC70

'h' : str[9]의 주소:008FFC71

'e' : str[10]의 주소:008FFC72

' ' : str[11]의 주소:008FFC73

'm' : str[12]의 주소:008FFC74

'o' : str[13]의 주소:008FFC75

'n' : str[14]의 주소:008FFC76

'e' : str[15]의 주소:008FFC77

'y' : str[16]의 주소:008FFC78



strstr

문자열에서 임의의 문자열을 찾을 수 있는 함수가 string.h에 존재합니다. 바로 strstr이라는 함수이지요.

char *strstr( char *str1, const char *str2);


- str1 : 전체 문자열을 의미합니다. str1이 이제 문자열을 찾을 대상이 되지요.

- str2 : 찾을 문자열을 의미합니다. 이 문자열을 str1에서 찾는 것입니다.


반환값 : str1에서 str2를 찾는다면 그 시작주소를 반환하게 됩니다. 찾지못하면 NULL을 반환합니다.


이제 예제를 보면서 함수를 어떻게 사용하는지 보도록 하지요.


▼strstr source code

#include <stdio.h>
#include <string.h>
int main() {

	char str[64] = "When I was young, I was ugly. But now, I'm still ugly";
	char *word = "ugly";
	char *ptr = strstr(str, word);
	int jump = strlen(word);
	int found = 0;
	while (ptr != NULL) {
		printf("%s\n", ptr);
		ptr = strstr(ptr + jump, word);
		found++;
	}

	printf("단어 갯수 :%d\n", found);
}

위의 코드는 str이라는 문자열에서 word라는 문자열을 찾습니다. 한번만 찾는게 아니고 계속해서 찾는거죠.
그러기 위해서 만약 단어를 찾으면 그 다음부터 찾아야하죠. 물론 ptr+1로 그냥 바로 다음 문자부터 찾으면 되겠지만 조금 더 많이 건너 뛰기 위해서 jump라는 변수를 사용한것 뿐입니다. 




그리고 found는 str에 그 word가 몇개나 존재하는지 알려줍니다.

아차, strstr 역시 str의 문자열 중 word와 일치한다면 일치한 str의 시작 주소를 넘겨주게 됩니다.
못 믿겠으면 직접 실험해보도록 하세요.

이제 결과를 보면서 확인해보세요.

결과

ugly. But now, I'm still ugly

ugly

단어 갯수 :2



여기까지 문자열 처리함수를 2개나 알아보았는데요. 물론 저의 설명이 허접해서 이해를 못하는 부분이 있을 수 있으니, 모르면 그냥 외워서 사용하도록 합시다.

반응형
블로그 이미지

REAKWON

와나진짜

,