반응형

개요

 문자열은 최소한 문자 한개 이상이 보여 있는 것을 의미한다. 물론 프로그래밍 언어에서는 열(array)형태의 자료형 안에 한 글자라도 들어 있어도 문자열로 취급한다. 문장의 개념과 혼동이 가능하겠으나 문장의 단위는 인간의 언어에서 구분하는 기준이고, 문자열은 여러 문장도 담을 수 있기 때문에 좀 더 다른 개념으로 이해하는 것이 좋다.

 컴퓨터를 사용한 이후 오랜 시간 동안 프로그래머들은 경험상 문자 기준으로 글자를 다루는 것 보다 문자열 단위로 다루는 것이 편리 하다는 것을 알게 되었다. 이러한 흔적으로 C 같은 오래된 언어에는 문자열을 다루는 기본 자료형이 없다. 문자열은 기본적으로 순서가 있는 문자들을 다루기 때문에 파이썬의 리스트 자료형과 비슷한 특징을 가지고 있다.

(해당 예제들은 IDLE Shell 혹은 python shell 에서 실행하는 것이 편하다)

문자열 정의

 문자열을 정의 하는 방법은 쌍따옴표로 시작해서 쌍따옴표로 끝나거나 따옴표로 시작해서 따옴표로 끝나면 된다. 쌍따옴표로 시작한 문자열 내에서의 따옴표는 단순한 문자 기호로 인식이 되며, 반대로 따옴표로 시작한 문자열 내에서 쌍따옴표는 문자 기호로 인식된다.

 만약 쌍따옴표 내에서 쌍따옴표를 문자 기호로 인식을 시키기 위해서는 앞에 역 슬래스(혹은 한국원화 기호)를 해주면 된다. 이는 쌍따옴표로 시작한 문자열 중간에 쌍따옴표를 그냥 넣게 되면, 앞에서 정의한 문자열 문법에 의해서 해당 위치까지 문자열이 끝나는 것으로 인식 되기 때문이다.

"min: hello"
'han: hello'
# 둘다 동일한 문자열

"min: 'hello'"
# 따옴표는 문자 기호로 인식됨

'han: "hello"'
# 쌍따옴표는 문자 기호로 인식됨

"min: \"hello\""
# 문자열 내에서 \기호 뒤에 있는 따옴표는 문자 기호로 인식됨

역슬래시 특수문자

 문자열 내에서 특정한 기호를 사용하기 위해서는 역슬러시를 사용하여 표현할 수 있다. 앞의 쌍따옴표나 따옴표의 경우 상황에 따라서 특수문자로 사용된 경우이다.

 즉, 줄바꿈, 탭, 앞줄 부터 시작을 표시하는 특수기호가 존재한다. 이러한 특수 문자를 표현할 경우 '\'(역슬러시)를 사용하여 표현한다. 이러한 표기법은 오래전부터 사용되었기 때문에 다른 프로그래밍 언어에서도 비슷하게 사용된다.

string 표기 이름 의미
\n 개행문자(Line Feed) 한줄 아래로 이동
\t 탭(tab) 탭키를 누른 것 만큼 이동
(일반적인 탭은 7, 8칸을 뛴 것과 같다)
\r 개행문자
(Carriage Return)
커서(글자를 쓰는 칸)를 현재 줄 앞으로 이동(윈도우즈 내부에서 사용함)
\' 작은 따옴표 작은 따옴표 표기
\" 큰 따옴표 혹은 쌍따옴표 큰 따옴표 표기
\\ 역 슬러시 역슬러시 표기

 여담으로 윈도우즈에서는 파일 경로를 표기하기 위한 구분자로 역슬러시를 사용하다 보니 해당 경로를 문자열로 받게 될 경우 역 슬래시가 2번 표기되는 것을 볼 수 있다. 하지만, 실제로 print() 로 화면에 출력하거나 파일로 저장할 경우에는 하나만 보이게 된다.

Formatter

 초기 프로그램들이 사람과 소통하는 가장 간단한 방법은 문자열을 화면에 보여주는 것이다. 특히 세금 계산서나 은행에서 사용하는 공문서들은 형식(Format)이 정해진 경우가 많다. 이처럼 형태가 정해진 문자열을 다룰 경우 많이 사용되는 방식이다.

 기본적으로 포맷 형식에는 샘플이 되는 문장이 있고 이를 어떻게 처리하느냐는 이후 문법 방식에 따라서 다르다.

%

 파이썬에서 가장 초기에 사용되던 방식이다. C 의 printf() 함수의 방식과 비슷하여 printf 방식 포멧팅이라고도 한다. python 2 에서 주로 사용된 방식으로 오래된 소스코드를 보면 쉽게 볼 수 있다. 샘플이 되는 문장에 변형이 가능한 자리에는 %d, %f, %s 와 같은 미리 정의 되어 있는 특수문자를 넣고 해당되는 값에 순서대로 넣는 것이 가능하다.

a = "%s님의 잔액은 %d원 입니다.\n이자율 %f\%" % ("오리", 101, 3.3)
print(a)
# 오리님의 잔액은 101원 입니다
# 이자율 3.300000100%

실수인 숫자의 경우 자리수를 제한 해야하는 경우에는 자리수에 해당하는 값도 추가 해줘야 한다.

a = "%s님의 잔액은 %d원 입니다.\n이자율 %.2f\%" % ("오리", 101, 3.3)
print(a)
# 오리님의 잔액은 101원 입니다
# 이자율 3.30%

format()

 권장하는 방식 중 하나이다. str 형에는 내부에 format() 함수가 들어 있어 해당 함수를 호출하여 문자열 내에 들어간 변수를 넣어주면 된다. 순서를 명시해 줄 수 도 있고 안해 줄 수도 있다.

 가장 많은 고민이 들어간 문법이기 때문에 공식 문서에서 내용이 방대한 편이다.

a = "{}님의 잔액은 {}원 입니다.\n이자율 {}%".format("오리", 101, 3.3)
print(a)
# 오리님의 잔액은 101원 입니다
# 이자율 3.30000001%
b = "{1}님의 잔액은 {0}원 입니다.\n이자율 {2}%"
b = b.format(101, "오리", 3.3)
print(b)
# 오리님의 잔액은 101원 입니다
# 이자율 3.3%

f-string

 python 3.6 부터 지원한 방식이다. 직관적인 편이기 때문에 권장하고 있다. 문자열의 시작전 f로 시작하여 중괄호 안에 변수가 되는 값 혹은 수식을 직접 삽입할 수 있다.

a1 = "오리"
a2 = 101
a3 = 3.3
a = f"{a1}님의 잔액은 {a2}원 입니다.\n이자율 {a3}%"
print(a)
# 오리님의 잔액은 101원 입니다
# 이자율 3.30000001%

 포멧이 되는 표현식(expression)의 경우 키워드가 아닌 중괄호를 표현하고 싶은 경우 중복해서 사용하면 기호로 인식된다.

이렇게 포멧 문자를 간단히 확인했는데, 자신이 초급 이상으로 좀 더 자세한 것을 알기 위해서는 공식문서를 확인해보면 된다.

문자열과 연산

문자열을 편의상 string 혹은 str로 표현을 한다.

str + str

 문자열과 문자열을 더 할 수 있다. 이 경우 두 문자열이 합쳐진 하나의 문자열이 된다.

a = "ba"
b = "poo"

c = a + b
# c == "bapoo"

str += str

 연산자의 좌측 문자열과 우측 문자열을 합친다음에 왼쪽 변수에 대입을 한다.

a = "hello"
b = "world"
a += b
a
# "helloworld"

str * int

문자열에 숫자를 곱한 경우 해당 문자열을 반복해서 더한다.

a = "-" * 8
a
# "--------"

str *= int

연산자의 좌측 문자에 우측 숫자만큼 반복한 문자열로 대입한다.

a = "-"
a *= 8
a
# --------

 

문자열 함수

문자열에 사용이 가능한 내장형 함수이다. 함수에 대한 설명은 이후 함수 항목에서 설명한다.

str()

숫자 타임의 int, float ㅎ여태로 자료형을 문자열로 변환 해준다.

a = 10
b = str(a)
b
# "10"

len()

문자열이 들어 잇는 문자열의 길이를 반환한다. 공백이나 줄 바꿈 문자도 하나의 문자로 인식한다. 문자열 뿐만 아니라 길이가 있는 list 형에서도 사용이 가능하다. 다만, list 자료형에 대해서는 나중에 다룬다.

a = "hello"
len(a)
# 5

b = "안녕"
len(b)
# 2

주의할 점

문자의 경우 이전에 공부한 문자 code 에 의해서 문자 종류에 따라서 한 문자를 저장하는 바이트 크기가 다르다. 즉, 문자열이 차지는 하는 메모리 용량과 문자의 길이는 다른 개념임을 인지해야 한다. 그리고 임베디드 같은 저수준 프로그래밍 하는 환경에서는 적은 메모리를 사용해야 하는 경우가 있기 때문에 이에 대해서도 주의 해야 한다. Python 에서 문자열이 차지하는 바이트 크기를 알기 위해서는 문자열을 bytes로 형변환을 하여 len() 함수를 사용하면 된다.

 

반응형

'Python > 배경이 있는 파이썬' 카테고리의 다른 글

튜플(Tuple)  (1) 2024.04.27
리스트(list)  (0) 2024.04.27
문자 code  (0) 2024.04.24
숫자형(int, float)  (0) 2024.04.24
변수(variable)와 상수(constant)  (0) 2024.04.23
반응형

C : 구조체를 네임스페이스처럼 사용하기

알게된 배경

리눅스 시스템에서 네트워크 프로그래밍을 공부할 때 참조한 책이 하필 C로 설명이 되어 있는 책이었다. 덕분에 C++과 달리 요즘에는 자료를 찾기 힘들기 때문에 필요한 정보를 처리하기 위해서 직접 함수를 만들어야 하는 경우가 많았다.

 함수가 많아지면 발생되는 문제는 역시 작명문제이다. 그러나 C는 네임스페이스나 클래스 기능이 제공되지 않기 때문에 구조체(struct)와 포인터의 조합으로 비슷하게 흉내내서 구현할 수 있다.

 그러나 타이핑 해야할 양이 급증하게 되므로 가능하면, C로 코딩해야 하는 상황을 최대한 벗어나길 바란다.


간략한 원리

구조체가 전역으로 선언이 되어 있어야 하며, 함수들은 포인터로 연결되어 있어야 한다. 그리고 이렇게 선언된 구조체는 외부 참조가 가능하도록 선언을 해야 네임스페이스 혹은 클래스처럼 사용할 수 있다.


구현 예시

예시로 문자열의 뒤쪽의 단어가 일치하는지 검사하는 함수를 구조체내의 함수로 구현한다. 확장자가 포함된 파일이름의 확장자 검사하는 용도로 사용될 수 있다.

헤더파일)

// ns_util.h
#pragma once

typedef enum{ false, true } bool;

struct ns_util_tools
{
    bool (*isHasBackword(const char* str, const char* backword);
};
// 아래의 struct가 존재하니 이 헤더파일을 인클루드 하면 사용할 수 있음
extern const struct ns_util_tools ns_util;

C파일)

// ns_util.c
#include <string.h>
#include "ns_util.h"
bool ns_util__isHasBackword(const char* str, const char* backword)
{
    int str_len, backword_len;
    int i;
    str_len = strlen(str);
    backword_len = strlen(str);
    for(i=0; i<backword_len; ++i)
    {
        if(str[str_len -i] != backword[backword_len -i])
            return false;
    }
    return true;
}
// 실제로 네임스페이스 처럼 사용될 구조체
const struct ns_util_tools ns_util = {
    .isHasBackword = ns_util__isHasBackword
};


다른파일에서 호출)

// main.c
#include <stdio.h>
#include "ns_util.h"

int main(int argc, char* argv[])
{
    char* str = "main.exe";
    if(ns_util.isHasBackword(str, ".exe"))
        printf("%s is exe file!!", str);
    else
        printf("%s is What is?", str);

    return 0;
}



 이로써 C로써도 충분히 객체지향으로 코딩이 가능하다는 것을 알 수 있다. 그렇지만, C로 프로젝트 진행하는 것은 가능하면 피하고 싶다.

반응형
반응형

C : 문자열 숫자 변환

작성계기

이전부터 정리를 하려 했으나 게으름으로 이제야 정리를 하게 되었다. 문자열을 숫자로 바꿔야 하는 경우는 굉장히 많기 때문에 유용하다. 한편으로는 간단하게 직접 똑같은 기능을 하는 함수를 간단히 만들 수 있다(본인은 atoi()를 늦게 알게 되어서 필요할때 직접 구현을 하였었다.


atoi()

헤더 파일: stdlib.h

선언 구조: int atoi(const char* str);

리턴: 정상적으로 작동될 경우 정수를 반환하고, 실패할 경우 아무것도 반환하지 않는다.

부가 설명: 함수 이름은 a는 문자열, i는 int의 첫 글자를 따서 문자열을 정수로 바꾼다는 의미로 지어진 이름이다. 따라서 atoi() 역이 되는 함수는 itoa()가 되어야 한다.


직접 구현해보기

atoi()와 같은 기능을 하는 함수를 간단히(?) 다음과 같이 구현할 수 있다.


// 한문자를 정수 숫자로 반환하는 함수
#include <string.h>

int char2int(const char ch)
{
    char index[10] = "0123456789";
    int t;
    for(t=0; t<10; ++t)
    {
        if(index[t] == ch)
            return t;
    }
    return -1;
}

// 10의 제곱수를 반환하는 함수
int pow10(const int n)
{
    int tmp;
    int num = 1;
    for(tmp = n; tmp>0; --tmp)
        num *= 10;
    return num;
}

// atoi()와 같은 역할을 하는 함수
int str2int(const char* str)
{
    int strLen = strlen(str);
    int op = 1;          // 부호
    int n = strLen;    // 자리수
    int num = 0;       // 결과값
    int t = 0;
    for(t=0; t<strlen; ++t)
    {
        int tmp = 0;
        if(0== t && '-' == str[0])
        {
            op = -1;
            --n;
            continue;
        }
        if(-1 == tmp)
            return;
        num += tmp*pow10(n);
    }
    return num*op;
}

조금 차이지만 여전히 C++보다 C가 더 불편하니 가능하면, 표준함수에서 제공하는 것을 소중히 여기도록 하자.

반응형

+ Recent posts