맨위로가기

문자열

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

문자열은 기호들의 유한한 시퀀스를 의미하며, 컴퓨터 과학에서 널리 사용되는 데이터 형식이다. 문자열 처리 알고리즘은 문자열 검색, 조작, 정렬, 정규 표현식, 구문 분석, 시퀀스 마이닝 등에 활용되며, 문자열론이라는 이론으로 발전했다. 대부분의 프로그래밍 언어는 문자열을 처리하기 위한 데이터 형식을 제공하며, 가변 문자열과 불변 문자열의 두 가지 유형으로 나뉜다. 문자열은 ASCII, 유니코드 등 다양한 문자 인코딩 방식을 통해 문자를 표현하며, C언어의 널 종료 문자열, 파스칼 문자열 등 표현 방식도 다양하다. 문자열 관련 언어 및 유틸리티는 문자열 처리를 쉽게 하도록 설계되었으며, 형식 언어 이론에서는 문자열의 길이, 결합, 부분 문자열, 접두사, 접미사 등의 연산을 정의한다. 문자열의 메모리 레이아웃과 저장 방식은 버퍼 오버플로우, 코드 삽입 공격 등 보안 문제와 관련이 있으며, 입력 유효성 검사를 통해 이러한 문제를 예방해야 한다.

더 읽어볼만한 페이지

  • 문자열 알고리즘 - 구문 분석
    구문 분석은 입력 데이터를 구조화된 형태로 변환하는 과정으로, 컴퓨터 언어에서는 소스 코드를 분석하여 추상 구문 트리를 생성하고, 자연어 처리에서는 텍스트의 문장 구조와 의미를 분석한다.
  • 문자열 - 빈 문자열
    빈 문자열은 형식 언어 이론에서 길이가 0인 문자열을 의미하며 프로그래밍 언어에서 유효한 문자열로 취급되고, 0을 표현하거나 빈 줄을 나타내는 데 사용된다.
  • 문자열 - 문자열 연결
    문자열 연결은 프로그래밍 언어에서 문자열을 결합하는 연산으로, `+` 연산자나 별도의 연산자를 사용하며, 런타임 또는 컴파일 시점에 수행될 수 있고, 형식 언어 이론으로 확장되어 음성 합성 등 다양한 분야에서 활용된다.
  • 문장 성분 - 목적어
    목적어는 문법에서 동사의 행위나 작용의 대상이 되는 문장 성분으로, 한국어에서는 '을/를'과 같은 조사가 붙어 형성되며, 영어에서는 직접 목적어, 간접 목적어, 전치사 목적어 등으로 나뉜다.
  • 문장 성분 - 부정사
    부정사는 동사의 한 형태로, 여러 언어에서 다양한 문법적 기능을 수행하며, 명사, 형용사, 부사의 역할을 하고 시제, 상, 태를 표시하는 굴절 형태를 가지며, 영어, 독일어, 라틴어 등에서 활발하게 사용된다.
문자열

2. 문자열 처리 알고리즘

문자열을 처리하기 위한 다양한 알고리즘이 있으며, 각 알고리즘은 다양한 장단점을 가지고 있다. 경쟁 알고리즘은 실행 시간, 저장 요구 사항 등을 기준으로 알고리즘 분석을 통해 분석할 수 있다. '''문자열론'''이라는 이름은 1984년 컴퓨터 과학자 즈비 갈릴에 의해 문자열 처리에 사용되는 알고리즘 및 데이터 구조 이론을 지칭하기 위해 만들어졌다.[18][19][20]

알고리즘의 일부 범주는 다음과 같다.



고급 문자열 알고리즘은 종종 접미사 트리 및 유한 상태 기계를 포함한 복잡한 메커니즘과 데이터 구조를 사용한다.

2. 1. 문자열 검색 알고리즘

문자열을 처리하기 위한 다양한 알고리즘 중 하나로, 주어진 부분 문자열이나 패턴을 찾는 문자열 검색 알고리즘이 있다.

2. 2. 문자열 조작 알고리즘

문자열을 처리하기 위한 다양한 알고리즘의 한 범주로, 주어진 문자열을 변경하거나 다른 문자열과 결합하는 등의 조작을 수행하는 문자열 조작 알고리즘이 있다.

2. 3. 정렬 알고리즘

문자열을 처리하기 위한 다양한 알고리즘 중 하나로, 문자열들을 특정 기준에 따라 순서대로 배열하는 정렬 알고리즘이 있다.

2. 4. 정규 표현식 알고리즘

문자열을 처리하기 위한 알고리즘의 한 종류로 정규 표현식 알고리즘이 있다.

2. 5. 구문 분석 알고리즘

문자열 파싱(구문 분석)은 문자열의 구조를 분석하는 알고리즘으로, 문자열 처리에 사용되는 주요 알고리즘 유형 중 하나이다.

2. 6. 시퀀스 마이닝

문자열 처리를 위한 알고리즘의 한 종류로 시퀀스 마이닝이 있다.

3. 문자열의 목적 및 역사

문자열의 주요 목적은 단어와 문장처럼 사람이 읽을 수 있는 텍스트를 저장하는 것이다. 컴퓨터 프로그램에서는 사용자에게 정보를 전달하거나[2] 사용자로부터 입력을 받는 데 문자열을 활용한다. 또한, 사람이 직접 읽을 목적이 아니더라도 문자로 표현된 데이터를 저장하는 데 사용될 수도 있다.

문자열의 다양한 사용 예시와 목적은 다음과 같다.


  • "파일 업로드 완료"와 같은 메시지는 소프트웨어가 최종 사용자에게 보여주는 대표적인 문자열이다. 프로그램의 소스 코드에서는 보통 문자열 리터럴 형태로 존재한다.
  • "오늘 새 직장을 얻었어요"처럼 사용자가 입력한 텍스트는 소셜 미디어의 상태 업데이트 등에 사용된다. 이러한 문자열은 프로그램 내부에 고정된 값이 아니라 데이터베이스 등에 저장되는 경우가 많다.
  • "AGATGCCGT"와 같은 알파벳 데이터는 DNA의 염기 서열을 나타내는 예시이다.[3]
  • "?action=edit"과 같은 컴퓨터 설정이나 매개변수는 URL의 쿼리 문자열 형태로 사용된다. 이런 문자열은 어느 정도 사람이 읽을 수 있도록 만들어지기도 하지만, 주된 목적은 컴퓨터와의 통신이다.


일반적으로 "문자열"이라고 하면 문자의 나열을 의미하지만, 문맥에 따라서는 "비트 문자열"처럼 문자 외의 데이터나 컴퓨터 레코드의 순서를 가리키는 데 사용될 수도 있다.[8]

3. 1. 역사

"문자열"이라는 단어가 일렬, 연속 또는 일련으로 배열된 항목을 의미하는 용례는 수 세기 전까지 거슬러 올라간다.[4][5] 19세기 조판사들은 종이에 인쇄된 활자 묶음을 "문자열"이라고 불렀으며, 이 문자열의 길이를 측정하여 조판사의 임금을 결정하기도 했다.[6][8][7]

이후 "문자열"은 수학, 기호 논리, 언어 이론 분야에서 "특정 순서의 기호 또는 언어 요소의 시퀀스"라는 보다 형식적인 의미로 사용되기 시작했다. 이는 기호 자체의 배열 순서에 초점을 맞추고 그 의미는 별도로 다루는 접근 방식이었다.[8] 예를 들어, 논리학자 C. I. 루이스는 1918년 저서에서 수학적 시스템을 다음과 같이 설명했다.[9]

> 수학적 시스템은 인식 가능한 일련의 기호 묶음으로, 그중 일부는 처음에 선택되고 나머지는 기호에 할당된 의미와 무관한 규칙에 따라 수행된 연산에 의해 파생됩니다. 시스템이 소리나 냄새 대신 '기호'로 구성된다는 것은 중요하지 않습니다.

컴퓨터 과학 분야에서는 문자열 처리와 패턴 매칭 기능이 중요한 요소로 자리 잡았다. 진 E. 샘메트에 따르면, 컴퓨터를 위한 "최초의 현실적인 문자열 처리 및 패턴 매칭 언어"는 1950년대에 개발된 COMIT였으며, 1960년대 초에는 SNOBOL 언어가 그 뒤를 이었다.[10]

4. 프로그래밍 언어의 문자열 데이터 타입

프로그래밍 언어 비교 (문자열 함수) 문서도 참고할 수 있다.
문자열 데이터 타입은 형식적인 문자열을 모델로 한 데이터 타입이다. 문자열은 매우 중요하고 유용한 데이터 타입이기 때문에 거의 모든 프로그래밍 언어에서 구현된다. 일부 언어에서는 기본 자료형으로, 다른 언어에서는 복합 자료형으로 제공된다. 대부분의 고급 프로그래밍 언어 구문은 문자열 데이터 타입의 인스턴스를 나타내기 위해 특정 방식으로 따옴표로 묶인 문자열 표기를 허용하는데, 이를 리터럴 또는 문자열 리터럴이라고 한다.

문자열 처리는 수치 연산과 함께 컴퓨터의 기본적인 처리 작업 중 하나이다. 많은 프로그래밍 언어는 문자열을 다루기 위한 데이터형이나 서브루틴(절차, 함수, 메서드) 등을 제공한다. 예를 들어 C#처럼 문자열이 내장 기본형으로 제공되는 언어도 있고[27][28], C 언어처럼 문자열을 기본형으로 갖지 않는 언어도 있다. C 언어에서는 문자열을 배열포인터를 이용해 다루며, 문자열의 길이 관리나 메모리 관리에 프로그래머가 더 주의를 기울여야 한다.[32]

컴퓨터 내부에서 문자열은 문자 코드 규칙에 따라 숫자로 변환되어 저장되고 처리된다. 과거에는 ASCII와 같이 1바이트로 문자를 표현하는 방식이 주로 사용되었으나, 한글과 같이 문자 수가 많은 언어를 표현하기 위해 다양한 문자 인코딩 방식이 발전해왔다. 현대적인 언어들은 유니코드를 기반으로 다국어 문자열 처리를 지원하는 경우가 많다.

문자열을 메모리에 저장하고 관리하는 방식은 언어마다 다르며, 대표적으로 문자열 끝에 특정 문자를 두는 방식(널 종료 문자열)이나 길이를 별도로 저장하는 방식 등이 있다. 윈도우 환경의 BSTR처럼 두 방식을 혼합한 형태도 존재한다.[31]

C++(C++)와 같은 객체 지향 프로그래밍 언어나 동적 언어, 스크립트 언어 등 후대의 고수준 언어들은 문자열을 보다 직관적으로 다룰 수 있는 풍부한 기능과 라이브러리를 표준으로 제공하는 경향이 있다. 이러한 언어에서는 문자열이 길이 정보 등을 포함하는 캡슐화된 데이터 구조(객체)로 구현되는 경우가 많다.

문자열 상수를 코드 내에 표기할 때는 대부분의 언어에서 큰따옴표(`"`)를 사용하지만, 작은따옴표(`'`)를 사용하거나 둘 다 허용하는 언어도 있다.

문자열의 구현 방식, 문자 인코딩의 종류와 특징, 그리고 문자열의 내용을 변경할 수 있는지 여부(불변성/가변성)에 대한 자세한 내용은 하위 섹션에서 다룬다.

4. 1. 문자열 데이터 타입의 종류

일반적으로 문자열 데이터 타입에는 두 가지 유형이 있다.

  • '''고정 길이 문자열''': 컴파일 타임에 최대 길이가 정해지는 문자열이다. 이 방식은 문자열의 실제 사용 길이와 관계없이 항상 정해진 최대 길이만큼의 메모리를 사용한다.
  • '''가변 길이 문자열''': 런타임에 길이를 변경할 수 있는 문자열이다. 실제 필요한 만큼 메모리 공간을 유동적으로 사용하며(메모리 관리 참조), 현대 프로그래밍 언어에서는 대부분 이 방식을 채택한다. 물론 가변 길이 문자열이라도 사용 가능한 컴퓨터 메모리의 크기에 따라 길이에 제한을 받는다.


문자열의 길이는 별도의 정수 값으로 저장하거나, C 프로그래밍 언어처럼 문자열 끝에 특정 종료 문자(보통 모든 비트가 0인 널 문자)를 두어 표시하기도 한다.

4. 2. 문자 인코딩

문자열 데이터 형식이 문자를 표현하는 방식은 문자 인코딩에 따라 달라진다. 역사적으로 초기 컴퓨터 환경에서는 문자당 1바이트를 할당하는 방식이 일반적이었으며, 주로 ASCII나 EBCDIC와 같은 문자 집합에 기반했다. 이러한 인코딩 방식은 지역별로 차이가 있어, 서로 다른 인코딩을 사용하는 시스템 간에 텍스트를 주고받을 때 글자 깨짐 현상이 발생하는 경우가 많았다.[27][28]

중국어, 일본어, 한국어 (통칭 CJK)와 같이 문자의 수가 많은 언어들은 1바이트(256자)로는 모든 문자를 표현할 수 없었다. 이 문제를 해결하기 위해 멀티바이트 문자 인코딩 방식이 등장했다. 대표적인 예로 EUC 계열(예: 한국어 표현을 위한 EUC-KR), ISO-2022, Shift JIS 등이 있다. 이 방식들은 기존 ASCII 문자는 1바이트로 유지하면서 CJK 문자를 표현하기 위해 2바이트 이상을 사용했다. 그러나 이러한 멀티바이트 인코딩은 문자열 검색이나 자르기 등에서 문제를 일으키기도 했으며, 인코딩 방식에 따라서는 문자 경계를 식별하기 어렵거나(비자가 동기화 문제), 특정 바이트 값이 ASCII 문자와 충돌하는 등의 문제가 발생하기도 했다.[29][30][31]

이러한 복잡성과 비호환성 문제를 해결하기 위해 유니코드라는 국제 표준 문자 집합이 등장했다. 유니코드는 전 세계의 거의 모든 문자에 고유한 코드 포인트를 할당하여 문자 인코딩 문제를 단순화했다. 현대의 많은 프로그래밍 언어들은 유니코드 문자열을 기본적으로 지원한다.

유니코드를 실제 바이트 데이터로 표현하는 방식에는 여러 가지가 있으며, 대표적으로 UTF-8, UTF-16, UTF-32가 있다.

  • UTF-8: 가변 길이 인코딩 방식으로, ASCII 문자는 1바이트로 표현되어 기존 ASCII와 호환성을 유지하며, 다른 문자들은 길이를 가변적으로 조절하여 표현한다. 웹을 비롯한 다양한 환경에서 사실상의 표준으로 널리 사용되며, 이전 멀티바이트 인코딩들이 가졌던 문제점들을 상당 부분 해결하도록 설계되었다. 특히 한국어를 포함한 다양한 언어를 효율적으로 표현할 수 있다.
  • UTF-16: 주로 자바윈도우 내부 처리 등에서 사용되는 가변 길이 인코딩 방식이다. 기본 다국어 평면(BMP)의 문자는 2바이트로, 그 외의 문자는 4바이트(서로게이트 페어)로 표현한다.
  • UTF-32: 모든 문자를 고정된 4바이트로 표현하는 방식이다. 코드 포인트당 길이가 일정하다는 장점이 있지만, 메모리 사용량이 크다는 단점이 있다. 다만, 유니코드의 결합 문자나 음소 클러스터(grapheme cluster) 개념 때문에 UTF-32의 코드 포인트 하나가 반드시 화면상에 보이는 문자 하나와 일치하는 것은 아니다.[32]


프로그래밍 언어마다 문자열과 인코딩을 다루는 방식은 다르다. 예를 들어 C 언어는 전통적으로 널 문자로 끝나는 문자 배열(널 종료 문자열)을 사용하며, 문자 인코딩 처리는 프로그래머가 직접 관리해야 하는 경우가 많다.[33] 반면 자바, C#과 같은 후발 언어들은 유니코드(주로 UTF-16 기반)를 기본 문자열 타입으로 내장하여 다국어 처리를 보다 용이하게 지원한다.[34][35][36] 한국어 텍스트를 올바르게 처리하기 위해서는 해당 환경에서 지원하는 적절한 유니코드 인코딩 방식(주로 UTF-8)을 사용하거나, 필요에 따라 EUC-KR과 같은 레거시 인코딩과의 호환성을 고려해야 한다.

4. 3. 문자열 표현 방식

문자열을 컴퓨터 내부에서 표현하는 방식은 사용하는 문자 집합 (ASCII, 유니코드 등)과 문자 인코딩 (UTF-8, UTF-16 등) 방식에 따라 크게 달라진다. 초기의 문자열 구현은 주로 ASCII나 이를 확장한 ISO 8859 시리즈를 기반으로 설계되었으나, 현대의 구현은 더 넓은 범위의 문자를 지원하는 유니코드UTF-8, UTF-16 같은 다양한 인코딩 방식을 사용하는 경우가 많다.

일반적으로 문자열은 각 문자에 해당하는 문자 코드를 저장하는 가변 길이 배열과 유사하게 구현된다. 하지만 특정 인코딩 방식, 예를 들어 UTF-8을 사용하면 하나의 논리적 문자(예: 한글 '가')가 배열 내에서 하나 이상의 항목(바이트)을 차지할 수 있다. 이 때문에 문자열의 논리적 길이(문자 수)와 배열의 물리적 길이(사용된 바이트 수)가 달라질 수 있다. UTF-32 인코딩은 모든 문자를 고정된 4바이트로 표현하여 이러한 복잡성을 일부 해소한다.

"바이트 문자열"이라는 용어는 일반적으로 읽을 수 있는 문자만으로 구성된 문자열이 아닌, 바이트의 범용 시퀀스를 나타낸다. 이는 바이트가 임의의 값을 가질 수 있고, 특정 값이 종료 문자로 해석되지 않아야 함을 의미한다.

주요 문자열 표현 방식은 다음과 같다.

=== 널 종료 문자열 ===

문자열의 끝을 표시하기 위해 특별한 종료 문자를 사용하는 방식이다. 가장 대표적인 예는 C 언어에서 유래한 방식으로, 문자열의 마지막에 모든 비트가 0인 널 문자(NUL, `\0`)를 추가한다.[11] 이 때문에 C 문자열이라는 이름으로 널리 불린다.

이 방식에서 ''n''개의 문자로 이루어진 문자열은 종료 문자를 포함하여 총 ''n'' + 1개의 저장 공간(예: 바이트)을 차지하며, 이는 암시적 자료 구조에 해당한다. 널 종료 문자열의 가장 큰 특징은 문자열 자체에 종료 문자와 동일한 값을 가진 문자(즉, 널 문자)를 포함할 수 없다는 점이다. 또한 문자열의 길이를 알기 위해서는 처음부터 끝까지 문자를 하나씩 확인하며 종료 문자를 찾아야 한다.

예를 들어, 10바이트 크기의 버퍼에 문자열 "FRANK"를 널 종료 방식으로 저장하면 다음과 같다. 종료 문자(NUL) 뒤의 공간은 문자열에 포함되지 않으며, 다른 데이터의 일부이거나 의미 없는 값(쓰레기 값)일 수 있다. (이러한 형태의 문자열은 어셈블리 언어 지시어에 따라 ''ASCIZ 문자열''이라고도 불린다.)

문자FRANKNUL(garbage)(garbage)(garbage)(garbage)
ASCII/UTF-8 (16진수)4652414E4B006B656677



역사적으로 널 문자가 아닌 다른 특수 문자를 종료 문자로 사용한 경우도 있었다. 일부 어셈블리 시스템에서는 `$` 기호를, CDC 시스템에서는 `:` 기호를 사용했으며(이 문자는 0의 값을 가짐), ZX80과 같은 초기 컴퓨터는 BASIC 언어에서 문자열 구분 기호로 큰따옴표(`"`)를 사용하기도 했다.[12] IBM 1401과 같은 초기 컴퓨터는 특수한 워드 마크 비트를 사용하여 문자열의 시작(또는 끝)을 표시하기도 했다. 또한 초기 마이크로컴퓨터 소프트웨어 중 일부는 ASCII 코드가 사용하지 않는 최상위 비트를 문자열 종료 표시에 활용하기도 했다.[13]

=== 길이 접두어 방식 ===

문자열의 시작 부분에 문자열의 길이를 나타내는 숫자 값을 명시적으로 저장하는 방식이다. 이 방식은 파스칼 계열 언어에서 많이 사용되었기 때문에 파스칼 문자열(P-string)이라고도 불린다.

초기 구현에서는 길이를 1바이트로 저장하여 최대 문자열 길이가 255로 제한되었지만, 이후 16비트, 32비트 또는 64비트 워드를 사용하여 훨씬 긴 문자열을 표현할 수 있게 되었다. 길이를 미리 알 수 있으므로 문자열 길이를 확인하는 작업이 매우 빠르며(상수 시간 복잡도), 널 종료 방식과 달리 문자열 내에 어떤 값이든 포함할 수 있다는 장점이 있다. 길이를 나타내는 필드가 주소 공간 전체를 표현할 수 있다면, 문자열의 길이는 동적 메모리 할당으로 사용 가능한 메모리에 의해서만 제한된다.

길이 정보를 저장하기 위한 추가 공간이 필요하며(''n'' + ''k'', 여기서 ''k''는 길이를 저장하는 워드의 크기), 문자열 길이가 매우 커져서 길이 정보를 저장하는 필드의 크기 자체를 늘려야 할 경우, 문자열 데이터를 메모리 상에서 이동시켜야 하는 상황이 발생할 수 있다.

다음은 10바이트 버퍼에 문자열 "FRANK"를 길이 접두어 방식으로 저장한 예시이다. 첫 번째 바이트에 길이(5)가 저장되고, 그 뒤로 실제 문자 데이터가 온다.

구분길이FRANK(garbage)(garbage)(garbage)(garbage)
ASCII/UTF-8 (16진수)054652414E4B6B656677



=== 객체 지향 언어 방식 ===

객체 지향 프로그래밍 언어(C++, 자바, C# 등)에서는 문자열을 객체로 다루는 경우가 일반적이다. 이 객체들은 내부적으로 문자 데이터를 저장하는 배열(또는 배열을 가리키는 포인터)과 문자열의 길이를 나타내는 정보를 함께 가지고 있는 레코드나 클래스 형태로 구현된다.

```cpp

// 예시: 문자열 클래스의 내부 구조 (개념적 표현)

class string {

size_t length; // 문자열 길이를 저장하는 변수

char *text; // 문자 데이터가 저장된 메모리 영역을 가리키는 포인터

};

```

이러한 내부 구조는 보통 정보 은닉 원칙에 따라 외부에는 직접 노출되지 않으며, 사용자는 클래스가 제공하는 메서드(함수)를 통해 문자열에 접근하고 조작하게 된다. 필요에 따라 문자열을 저장하는 메모리 공간은 동적으로 할당되거나 확장될 수 있다. string (C++) 클래스도 이와 유사한 방식을 사용한다.

자바의 `java.lang.String` 클래스나 .NET의 `System.String` 클래스처럼 문자열을 불변 객체(immutable object)로 구현하는 경우가 많다. 불변 객체는 한번 생성되면 그 내용을 변경할 수 없으며, 문자열을 수정하는 연산(예: 이어붙이기)은 새로운 문자열 객체를 생성하여 반환한다. 문자열 내용을 직접 변경해야 하는 경우에는 자바에서는 `java.lang.StringBuffer` 클래스나 `java.lang.StringBuilder` 클래스를, .NET에서는 `System.Text.StringBuilder` 클래스[34]를 사용한다. Objective-C의 경우, 일반적인 `NSString` 클래스[35]는 불변이며, 편집 가능한 문자열형으로서 별도로 `NSMutableString` 클래스[36]가 준비되어 있다.

=== 기타 표현 방식 ===

위 방식들 외에도 특정 목적에 맞게 최적화된 다른 문자열 표현 방식들이 존재한다.


  • 로프(Rope): 매우 긴 문자열에 대해 삽입, 삭제, 병합 등의 연산을 효율적으로 수행하기 위해 설계된 트리 기반의 자료 구조이다.
  • 텍스트 편집기의 자료 구조: 텍스트 편집기는 대용량 텍스트의 편집 작업을 효율적으로 처리하기 위해 갭 버퍼, 줄의 연결 리스트, 피스 테이블 또는 로프와 같은 대체 시퀀스 데이터 구조를 사용하기도 한다. 이를 통해 삽입, 삭제, 실행 취소와 같은 특정 문자열 작업을 더 효율적으로 수행할 수 있다.[14]
  • 런 길이 인코딩이나 해밍 코드와 같은 기술을 사용하여 문자열 표현을 최적화할 수도 있다.


=== 프로그래밍 언어별 특징 ===

각 프로그래밍 언어는 문자열을 다루는 방식에 차이가 있다.

  • C 언어: 언어 자체에 내장된 문자열 타입이 없다. 주로 널 종료 문자열(문자 배열과 포인터)을 사용하며, 프로그래머가 직접 메모리 관리와 길이 확인에 주의해야 한다. 문자열 처리를 위한 표준 라이브러리 함수(`strcpy`, `strcat` 등)를 제공한다. C 언어의 배열은 제1급 객체가 아니므로 문자열도 제1급 객체가 아니다. 문자열 리터럴 표기법은 있지만, 실제 타입은 널 종료 고정 길이 문자 배열이다.[32] C95 표준부터 멀티바이트 문자와 와이드 문자형 `wchar_t`를 지원하기 시작했다.
  • C++: C 스타일 널 종료 문자열과 함께 표준 라이브러리의 `std::basic_string` 클래스 템플릿을 제공하여 객체 지향적인 문자열 처리를 지원한다. C 문자열과의 상호 운용성이 고려되어 있다.
  • 파스칼: 일부 확장된 버전(예: UCSD 파스칼, 확장 파스칼 등)에서 길이 접두어 방식의 가변 길이 문자열 타입(`string`)을 지원한다. 표준 파스칼(ISO 7185)에서는 문자 배열을 사용해야 했다.[29][30]
  • 자바, C#: 문자열을 기본적인 내장 타입 또는 핵심 클래스로 제공한다. 유니코드를 기반으로 하며(자바의 `char`는 UTF-16), 일반적으로 불변 객체로 구현된다. 문자열 리터럴은 보통 큰따옴표(`"`)로 표기한다. C#의 경우 `string` 키워드는 .NET의 `System.String` 타입의 별칭이다.[27][28] 자바의 자바 클래스 파일에서는 수정된 UTF-8(Modified UTF-8) 인코딩이 사용되기도 한다.[33]
  • Microsoft Windows 및 COM 환경에서는 널 종료와 길이 정보를 함께 사용하는 `BSTR` 데이터 구조가 사용되기도 한다.[31]


이처럼 다양한 표현 방식은 각각의 장단점을 가지며, 사용되는 프로그래밍 언어, 시스템 환경, 처리하려는 데이터의 특성에 따라 적합한 방식이 선택된다. 예를 들어, 널 종료 문자열은 널 문자를 포함할 수 없고, 길이 접두어 문자열은 길이 필드의 최대값에 의해 길이가 제한될 수 있지만, 적절한 프로그래밍을 통해 이러한 제약을 극복할 수 있다.

4. 4. 불변 문자열과 가변 문자열

일부 프로그래밍 언어에서는 문자열이 생성된 후에도 그 내용을 변경할 수 있는데, 이를 가변 문자열(mutable string)이라고 한다. 예를 들어 C++, Perl, 루비와 같은 언어들이 가변 문자열을 지원한다. C++의 표준 라이브러리에 포함된 'std::basic_string' 클래스 템플릿은 내부 버퍼로 사용되는 문자 배열의 요소를 직접 변경하는 것을 허용한다.

반대로 자바, 자바스크립트, Lua, 파이썬, Go와 같은 언어에서는 문자열의 값이 한번 정해지면 고정되어 변경할 수 없다. 내용을 바꾸려면 새로운 문자열 객체를 생성해야 한다. 이러한 문자열을 불변 문자열(immutable string)이라고 한다. 대표적인 예로는 자바의 'String' 클래스, .NET의 'System.String' 클래스[34], 그리고 Objective-C의 'NSString' 클래스[35]가 있다.

불변성은 장점과 단점을 모두 가지고 있다. 불변 문자열은 구조가 더 단순하고 여러 스레드에서 동시에 접근해도 안전한 스레드 안전 상태를 보장하지만, 문자열을 수정할 때마다 메모리에 새로운 복사본을 계속 만들어야 하므로 비효율적일 수 있다.

이러한 단점을 보완하기 위해, 불변 문자열을 기본으로 사용하는 언어들은 문자열을 효율적으로 수정해야 할 때 사용할 수 있는 별도의 가변 타입을 제공하는 경우가 많다. 예를 들어, 자바에는 'StringBuilder' 클래스와 스레드 안전성을 강화한 'StringBuffer' 클래스가 있다. .NET 환경에서는 'System.Text.StringBuilder' 클래스[34]를 사용한다. Objective-C와 Cocoa 환경에서는 편집 가능한 문자열 타입으로 'NSMutableString' 클래스[36]가 준비되어 있다.

5. 문자열 관련 언어 및 유틸리티

문자열은 매우 유용한 데이터 형식이므로, 문자열 처리를 쉽게 할 수 있도록 여러 프로그래밍 언어가 설계되었다. 대표적인 예는 다음과 같다.



많은 유닉스 유틸리티는 간단한 문자열 조작 기능을 수행하며, 일부 강력한 문자열 처리 알고리즘을 쉽게 프로그래밍하는 데 사용될 수 있다. 파일과 유한 스트림은 문자열로 볼 수 있다.

Perl, 파이썬, 루비, Tcl을 포함한 많은 스크립트 프로그래밍 언어는 텍스트 작업을 용이하게 하기 위해 정규 표현식을 사용한다. Perl은 특히 정규 표현식 사용으로 유명하며,[21] 다른 많은 언어와 응용 프로그램은 Perl 호환 정규 표현식을 구현한다.

Perl이나 루비 같은 일부 언어는 문자열 보간 기능을 지원하여, 문자열 리터럴 안에 임의의 표현식을 평가하고 그 결과를 포함시킬 수 있다.

또한, 멀티미디어 제어 인터페이스(MCI), 임베디드 SQL, printf와 같은 일부 API는 해석해야 할 명령어를 보관하는 데 문자열을 사용한다.

6. 형식 이론

Σ를 서로 구별되고, 모호하지 않은 기호(문자라고도 함)의 유한 집합이라고 하자. 이를 알파벳이라고 한다. Σ에 대한 '''문자열'''(또는 '''단어''',[23] 또는 '''식'''[24])은 Σ에서 가져온 기호들의 유한한 수열이다.[25] 예를 들어, Σ = {0, 1}이면, ''01011''은 Σ에 대한 문자열이다.

문자열 ''s''의 ''길이''는 ''s''에 있는 기호의 수(수열의 길이)이며, 음이 아닌 정수가 될 수 있다. 이는 종종 |''s''|로 표기된다. ''빈 문자열''은 길이가 0인 Σ에 대한 고유한 문자열이며, ''ε'' 또는 ''λ''로 표기된다.[25][26]

길이 ''n''인 Σ에 대한 모든 문자열의 집합은 Σ''n''으로 표기된다. 예를 들어, Σ = {0, 1}이면, Σ2 = {00, 01, 10, 11}이다. 모든 알파벳 Σ에 대해 Σ0 = {ε}이다.

어떤 길이든 Σ에 대한 모든 문자열의 집합은 Σ의 클레이니 폐쇄이며, Σ*로 표기된다. Σ''n''의 관점에서 보면,

:\Sigma^{*} = \bigcup_{n \in \mathbb{N} \cup \{0\}} \Sigma^{n}

예를 들어, Σ = {0, 1}이면, Σ* = {ε, 0, 1, 00, 01, 10, 11, 000, 001, 010, 011, ...}이다. Σ* 집합 자체는 가산 무한이지만, Σ*의 각 요소는 유한한 길이의 문자열이다.

Σ에 대한 문자열의 집합(즉, Σ*의 모든 부분 집합)을 Σ에 대한 ''형식 언어''라고 한다. 예를 들어, Σ = {0, 1}인 경우, 0의 개수가 짝수인 문자열의 집합, 즉 {ε, 1, 00, 11, 001, 010, 100, 111, 0000, 0011, 0101, 0110, 1001, 1010, 1100, 1111, ...}는 Σ에 대한 형식 언어이다.

''결합''은 Σ*에서 중요한 이항 연산이다. Σ*에 있는 두 문자열 ''s''와 ''t''에 대해, 이들의 결합은 ''s''의 기호 시퀀스 다음에 ''t''의 문자 시퀀스를 차례로 나열한 것으로 정의되며, ''st''로 표시한다. 예를 들어, Σ = {a, b, ..., z}이고, ''s'' = ''bear'', ''t'' = ''hug''라면, ''st'' = ''bearhug''이고 ''ts'' = ''hugbear''이다.

문자열 결합은 결합 법칙을 따르지만, 교환 법칙은 성립하지 않는 연산이다. 빈 문자열 ε는 항등원 역할을 한다; 모든 문자열 ''s''에 대해, ε''s'' = ''s''ε = ''s''이다. 따라서, 집합 Σ*와 결합 연산은 Σ에 의해 생성된 자유 모노이드인 모노이드를 형성한다. 또한, 길이 함수는 Σ*에서 음이 아닌 정수로의 모노이드 준동형 사상을 정의한다(즉, L: \Sigma^{*} \mapsto \mathbb{N} \cup \{0\}와 같은 함수로, L(st)=L(s)+L(t)\quad \forall s,t\in\Sigma^*를 만족한다).

문자열 ''s''는 ''t'' = ''usv''를 만족하는 (아마도 빈) 문자열 ''u''와 ''v''가 존재할 경우 ''t''의 ''부분 문자열'' 또는 ''요소''라고 한다. "의 부분 문자열이다"라는 이항 관계는 Σ*에 대한 부분 순서 관계를 정의하며, 그 최소 원소는 빈 문자열이다.

문자열 ''s''가 문자열 ''t''의 접두사가 되려면 ''t'' = ''su''를 만족하는 문자열 ''u''가 존재해야 한다. 만약 ''u''가 비어 있지 않다면, ''s''는 ''t''의 ''진정한'' 접두사라고 한다. 대칭적으로, 문자열 ''s''가 문자열 ''t''의 접미사가 되려면 ''t'' = ''us''를 만족하는 문자열 ''u''가 존재해야 한다. 만약 ''u''가 비어 있지 않다면, ''s''는 ''t''의 ''진정한'' 접미사라고 한다. 접미사와 접두사는 ''t''의 부분 문자열이다. "의 접두사이다"와 "의 접미사이다" 관계는 모두 접두사 순서이다.

문자열의 반전은 동일한 기호를 갖지만 순서가 뒤바뀐 문자열이다. 예를 들어, ''s'' = abc(여기서 a, b, c는 알파벳의 기호)이면 ''s''의 반전은 cba이다. 자기 자신과 반대되는 문자열(예: ''s'' = madam)을 회문이라고 하며, 여기에는 빈 문자열과 길이가 1인 모든 문자열도 포함된다.

문자열 ''s'' = ''uv''는 ''t'' = ''vu''일 경우 ''t''의 회전이라고 한다. 예를 들어, Σ = {0, 1}이고 문자열 0011001은 0100110의 회전인데, 여기서 ''u'' = 00110이고 ''v'' = 01이다. 또 다른 예로, 문자열 abc는 abc 자체(''u''=abc, ''v''=ε), bca(''u''=bc, ''v''=a), cab(''u''=c, ''v''=ab)의 세 가지 서로 다른 회전을 갖는다.

문자열 집합에 대한 순서를 정의하는 것은 종종 유용하다. 알파벳 Σ에 전순서 (예: 사전순)가 있는 경우 Σ*사전식 순서라고 하는 전순서를 정의할 수 있다. 사전식 순서는 알파벳 순서가 전순서인 경우 전순서이지만, 알파벳 순서가 전순서인 경우에도 임의의 비자명 알파벳에 대해 잘 정렬되지 않음은 아니다. 예를 들어, Σ = {0, 1}이고 0 < 1인 경우 Σ*에 대한 사전식 순서는 ε < 0 < 00 < 000 < ... < 0001 < ... < 001 < ... < 01 < 010 < ... < 011 < 0110 < ... < 01111 < ... < 1 < 10 < 100 < ... < 101 < ... < 111 < ... < 1111 < ... < 11111 ... 와 같은 관계를 포함한다. 이러한 순서와 관련하여, 예를 들어 무한 집합 { 1, 01, 001, 0001, 00001, 000001, ... }에는 최소 원소가 없다.

잘 정렬됨을 보존하는 다른 문자열 순서에 대해서는 Shortlex를 참조하십시오.

예시 알파벳에 대한 shortlex 순서는 ε < 0 < 1 < 00 < 01 < 10 < 11 < 000 < 001 < 010 < 011 < 100 < 101 < 0110 < 111 < 0000 < 0001 < 0010 < 0011 < ... < 1111 < 00000 < 00001 ... 이다.

형식 이론에서 문자열에 대한 여러 추가 연산이 일반적으로 발생한다. 이는 문자열 연산 문서에 나와 있다.

7. 보안 문제

문자열 데이터를 처리하는 방식은 프로그램의 보안에 영향을 미칠 수 있다. 특히 문자열을 메모리에 저장하는 방식에 따라 여러 보안 취약점이 발생할 수 있다.

대표적으로 널 문자를 사용하여 문자열의 끝을 표시하는 방식(널 종료 문자열)은 종료 문자가 누락될 경우 버퍼 오버플로우 문제에 취약하다.[11] 이는 프로그래밍 과정에서의 실수나 공격자가 의도적으로 데이터를 조작하여 발생할 수 있다. 버퍼 오버플로우는 할당된 메모리 공간을 넘어서 데이터가 기록되어 예기치 않은 동작이나 시스템 장악으로 이어질 수 있는 심각한 보안 문제이다.

문자열의 길이를 별도의 필드에 저장하는 방식 역시 안전하지 않을 수 있다. 만약 공격자가 길이 정보를 조작할 수 있다면, 프로그램은 잘못된 길이 정보를 바탕으로 메모리에 접근하게 된다. 이 경우, 프로그램 코드는 문자열 데이터가 실제로 저장된 메모리 범위를 벗어나 다른 데이터에 접근하거나 이를 변경할 위험이 있다. 따라서 이러한 방식에서는 문자열 데이터에 접근하기 전에 항상 범위 검사를 수행하여 메모리 접근이 유효한 범위 내에서 이루어지는지 확인해야 한다.

또한, 프로그램이 사용자로부터 문자열 데이터를 입력받는 경우에도 보안 문제가 발생할 수 있다. 사용자가 입력한 데이터가 예상된 형식이나 길이를 따르지 않을 수 있기 때문에, 프로그램은 입력된 문자열 데이터의 유효성 검사를 철저히 수행해야 한다. 만약 유효성 검사가 제대로 이루어지지 않으면, 공격자는 악의적인 코드를 포함한 문자열을 입력하여 코드 삽입 공격을 시도할 수 있다. 이는 프로그램의 비정상적인 동작이나 중요 정보 유출 등으로 이어질 수 있으므로, 외부 입력 데이터는 반드시 검증하고 안전하게 처리하는 것이 중요하다.

참조

[1] 웹사이트 Introduction To Java – MFC 158 G http://www.acsu.buff[...] 2016-03-03
[2] 웹사이트 Strings https://users.cs.uta[...]
[3] 웹사이트 DNA as a Biochemical Entity and Data String https://plant-breedi[...] 2019-11-14
[4] 백과사전 string Oxford at the Clarendon Press
[5] 웹사이트 string (n.) https://www.etymonli[...]
[6] 백과사전 string The Century Company
[7] 뉴스 Old Union's Demise 1898-01-11
[8] 백과사전 string Oxford at the Clarendon Press
[9] 서적 A survey of symbolic logic https://archive.org/[...] University of California Press
[10] 학술지 Programming Languages: History and Future https://redirect.cs.[...] 1972-07
[11] 서적 Computer Systems: A Programmer's Perspective http://csapp.cs.cmu.[...] Pearson Education 2007-08-06
[12] 웹사이트 An Assembly Listing of the ROM of the Sinclair ZX80 http://www.wearmouth[...] 2015-08-15
[13] 웹사이트 Design Notes for Tiny BASIC http://www.ittybitty[...] 2017-04-10
[14] 웹사이트 Data Structures for Text Sequences http://www.cs.unm.ed[...] 2016-03-04
[15] 웹사이트 strlcpy and strlcat - consistent, safe, string copy and concatenation. https://www.sudo.ws/[...] 2016-03-13
[16] 웹사이트 A rant about strcpy, strncpy and strlcpy. http://udel.edu/~pco[...] 2016-02-29
[17] 문서 No, strncpy() is not a "safer" strcpy()
[18] 웹사이트 The Prague Stringology Club http://www.stringolo[...] 2015-05-23
[19] 웹사이트 Former Dean Zvi Galil Named a Top 10 Most Influential Computer Scientist in the Past Decade https://www.engineer[...] 2021-03-18
[20] 서적 Jewels of stringology 2002
[21] 웹사이트 Essential Perl http://cslibrary.sta[...] 2012-04-21
[22] 웹사이트 x86 string instructions https://docs.oracle.[...] 2015-03-27
[23] 서적 Foundations of Discrete Mathematics PWS-Kent
[24] 서적 Mathematical Logic CRC Press
[25] 서적 Mathematical Methods in Linguistics Kluwer
[26] 서적 Introduction to Automata Theory, Languages, and Computation https://archive.org/[...] Addison-Wesley
[27] 웹사이트 文字列 - C# プログラミング ガイド | Microsoft Learn https://learn.micros[...]
[28] 웹사이트 組み込み型 - C# リファレンス - C# | Microsoft Learn https://learn.micros[...]
[29] 문서 UCSD Pascal: a portable software environment for small computers https://dl.acm.org/d[...]
[30] 문서 9.15.4.1. LPString https://icarus.cs.we[...]
[31] 문서 '[MS-DTYP]: BSTR | Microsoft Learn' https://learn.micros[...]
[32] 문서 String literals (C) - cppreference.com https://en.cpprefere[...]
[33] 문서 'Chapter 4. The class File Format | Java SE 8 Specifications > Java Virtual Machine Specification | Oracle' https://docs.oracle.[...]
[34] 문서 StringBuilder Class (System.Text) | Microsoft Learn https://learn.micros[...]
[35] 문서 NSString | Apple Developer Documentation https://developer.ap[...]
[36] Apple Developer Documentation NSMutableString https://developer.ap[...]
[37] 웹인용 Introduction To Java - MFC 158 G http://www.acsu.buff[...]



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com