Menu

C# 문자열: 길이, 비교, 이스케이프 문자, 축자 문자열과 여러 줄 문자열

C#에서 문자열이 동작하는 방식: 불변성, Length와 인덱싱, ==와 Equals와 string.Compare로 비교하기, 이스케이프 문자, 축자 @ 문자열과 여러 줄 텍스트, 원시 문자열 리터럴, null과 빈 문자열 검사, 문자 순회를 알아봅니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

C#의 string은 UTF-16 문자(char 값)의 시퀀스입니다. 참조 형식이지만 중요한 면에서는 값처럼 동작합니다. 불변이고, ==는 객체의 동일성이 아니라 텍스트를 비교합니다. string은 .NET 타입 System.String의 C# 키워드이며, 둘은 서로 바꿔 쓸 수 있습니다.

출력:

Porto
5
0
*****
hi
Porto has 5 letters

문자열은 불변입니다

문자열을 제자리에서 바꾸는 메서드는 없습니다. ToUpper, Replace, Trim을 비롯한 모든 메서드는 원본은 그대로 두고 새 문자열을 반환합니다. 반환값을 쓰지 않는 것은 아주 흔한 문자열 버그입니다:

출력:

[  maya  ]
[MAYA]
tea
tea and cake

불변성 덕분에 문자열은 스레드 간에 안전하게 공유할 수 있고 딕셔너리 키로 쓸 수 있습니다. 대신 루프에서 문자열을 조금씩 만들면 단계마다 새 문자열이 생깁니다. 그런 경우에는 StringBuilder를 쓰세요.

길이와 인덱싱

Length는 속성입니다(괄호 없음). 인덱서 s[i]는 0부터 세는 위치 i의 char를 반환하며 읽기 전용입니다:

출력:

7
A
1
IndexOutOfRangeException
XB-2931

C# 8 이상에서는 끝에서부터의 인덱스도 쓸 수 있습니다. code[^1]은 마지막 문자로, code[code.Length - 1]과 같습니다. 여러 문자를 한 번에 가져오려면 Substring을 참고하세요.

Length는 읽는 사람이 보는 문자가 아니라 UTF-16 코드 단위를 셉니다. 대부분 언어의 대부분 글자는 한 단위이지만, 이모지와 일부 드문 문자는 두 단위(서로게이트 쌍)를 쓰므로 "👍".Length는 2입니다.

문자열 비교

==와 !=는 대소문자를 구분해 문자를 비교합니다. 그 밖의 경우에는 비교 방식을 알려 주는 StringComparison 값을 넘기세요:

출력:

False
False
True
True
apple first
True
False
False
True

어떤 비교를 쓸까:

  • **Ordinal**은 문자의 숫자 코드를 비교합니다. 빠르고 예측 가능하며 모든 컴퓨터에서 같습니다. 식별자, 파일 이름, 키, 프로토콜 값처럼 사람에게 보여 주지 않는 모든 것에 쓰세요.
  • **OrdinalIgnoreCase**는 같은 방식이되 대소문자를 무시합니다. 파일 확장자나 HTTP 헤더처럼 대소문자를 구분하지 않는 검사에 맞습니다.
  • CurrentCulture(와 CurrentCultureIgnoreCase)는 사용자 언어의 규칙을 따르므로 그 언어의 사전처럼 단어를 정렬합니다. 사용자에게 보여 주는 목록을 정렬할 때 쓰세요.
  • **InvariantCulture**는 사용자의 언어 설정에 의존하지 않는, 문화권을 고려한 규칙을 씁니다. 그래도 세계화 라이브러리에는 의존합니다. 최신 .NET은 ICU를, .NET Framework는 Windows의 NLS를 쓰며, 둘은 일부 문자열을 다르게 정렬할 수 있습니다.

StringComparison 없이 쓰는 string.Compare(a, b)와 a.CompareTo(b)는 현재 문화권을 쓰므로 컴퓨터마다 결과가 달라집니다. a.ToLower() == b.ToLower()로 비교하는 것은 피하세요. 새 문자열을 두 개 할당하고, 일부 문화권에서 틀린 답을 냅니다(터키어의 점 있는 i와 점 없는 i가 대표적인 사례입니다).

a가 null일 때 a.Equals(b)를 호출하면 NullReferenceException이 발생하지만, a == b와 정적 메서드 string.Equals(a, b)는 null을 안전하게 처리합니다.

이스케이프 문자

일반 문자열 리터럴 안에서 백슬래시는 이스케이프 시퀀스를 시작합니다:

이스케이프의미
\n새 줄(라인 피드)
\r캐리지 리턴
\t탭
\\백슬래시
\"큰따옴표
\'작은따옴표(char 리터럴에서만 필요)
\0널 문자
\uXXXX4자리 16진 코드로 지정하는 UTF-16 문자, 예: \u00e9
\U0001F44D8자리 16진 코드로 지정하는 문자. U+FFFF보다 크면 char 값 두 개가 됩니다
\xH부터 \xHHHH1~4자리 16진수로 지정하는 문자(피하세요: 길이가 모호합니다)
\a, \b, \f, \v경고음, 백스페이스, 폼 피드, 수직 탭
\e이스케이프 문자, U+001B(C# 13)

출력:

Name:	Ana
City:	Porto
She said "hi"
C:\temp\report.txt
cafe = cafe
' is a quote char

"\d"처럼 인식되지 않는 시퀀스는 컴파일 오류(CS1009, unrecognized escape sequence)입니다. Windows 경로나 정규식을 일반 문자열로 쓰면 이 오류가 납니다.

축자 문자열과 여러 줄 문자열

리터럴 앞에 @를 붙이면 축자 문자열이 됩니다. 백슬래시는 그대로의 문자이고, 문자열이 여러 줄에 걸칠 수 있습니다. 남은 유일한 이스케이프는 큰따옴표 하나를 만드는 ""입니다.

출력:

C:\Users\ana\Documents\notes.txt
\d{3}-\d{4}
He said "ready" and left.
Rua das Flores 12
4050-262 Porto
Portugal
first line
second line

축자 여러 줄 문자열은 이어지는 줄의 들여쓰기를 포함해 따옴표 사이의 모든 것을 담습니다. 그래서 위처럼 보통 왼쪽 여백에 딱 붙여 씁니다. 문자열에 들어가는 줄바꿈은 소스 파일의 줄바꿈이므로, Windows 줄 끝으로 저장된 파일은 \r\n을 만듭니다.

C# 11은 두 문제를 모두 해결하는 원시 문자열 리터럴을 추가했습니다. 세 개 이상의 큰따옴표로 시작하고 끝나며, 이스케이프가 전혀 필요 없고, 닫는 따옴표가 들여쓰기된 만큼의 들여쓰기를 제거합니다:

// C# 11 and later
string json = """
    {
      "name": "Ana",
      "path": "C:\temp"
    }
    """;
// The 4 spaces before the closing """ are removed from every line.

내용 자체에 """가 있으면 네 개의 따옴표로 시작하고 끝내세요. 원시 리터럴은 보간과도 함께 쓸 수 있습니다($"""..."""). 문자열 보간을 참고하세요.

null, 빈 문자열, 공백

문자열 변수는 null(문자열이 아예 없음)이거나, 비어 있거나("", 길이 0), 공백만 담고 있을 수 있습니다. 두 정적 헬퍼가 NullReferenceException 위험 없이 이런 경우를 검사합니다:

출력:

null    empty: True   blank: True
""      empty: True   blank: True
"   "   empty: False  blank: True
"Ana"   empty: False  blank: False
True

사용자 입력을 검증할 때 원하는 것은 거의 항상 string.IsNullOrWhiteSpace입니다. string.Empty와 ""는 같은 값이며, 어느 쪽을 쓸지는 스타일 문제입니다.

문자 순회

문자열은 열거 가능하므로 foreach가 각 char를 방문합니다. char 타입에는 문자를 분류하는 정적 메서드가 있습니다:

출력:

letters=6 digits=4 upper=1 symbols=1
!6202tesnuS

문자열 합치기

+는 문자열을 이어 붙이며, 반대쪽이 어떤 타입이든 동작합니다(ToString()을 호출합니다). 많은 값을 합칠 때는 보간이나 string.Join을 우선 쓰세요:

출력:

Ana Silva, 31
Ana Silva, 31
AnaSilva
tea | coffee | juice
Total: 23
Total: 5

마지막 두 줄은 우선순위 함정을 보여 줍니다. +는 왼쪽부터 평가되므로, 왼쪽이 한 번 문자열이 되면 이후의 모든 +는 이어 붙이기입니다. 이어 붙이기 안의 산술 연산은 괄호로 감싸세요.

자주 묻는 질문

C#에서 문자열의 길이는 어떻게 구하나요?

Length 속성을 씁니다. "hello".Length는 5입니다. 메서드가 아니라 속성이므로 괄호가 없습니다. Length는 UTF-16 코드 단위를 세므로 이모지처럼 기본 다국어 평면 밖의 문자는 2로 셉니다. null 문자열에 호출하면 NullReferenceException이 발생합니다.

C#에서 문자열은 어떻게 비교하나요?

a == b는 텍스트를 비교하며 대소문자를 구분합니다. 대소문자를 무시하고 같은지 보려면 string.Equals(a, b, StringComparison.OrdinalIgnoreCase)를 쓰세요. 문자열을 정렬하거나 순서를 정하려면 string.Compare(a, b, StringComparison.Ordinal)이나 문화권을 고려한 비교를 쓰며, 이들은 음수, 0, 양수를 반환합니다.

C#에서 여러 줄 문자열은 어떻게 쓰나요?

리터럴 앞에 @를 붙여 축자 문자열로 만드세요. 여러 줄에 걸칠 수 있고, 백슬래시는 그대로이며, 큰따옴표는 ""로 씁니다. C# 11 이상에서는 """로 감싼 원시 문자열 리터럴도 여러 줄에 걸칠 수 있고, 공통 들여쓰기를 제거하며, 이스케이프가 전혀 필요 없습니다. \n이나 Environment.NewLine으로 줄을 이을 수도 있습니다.

C#의 축자 문자열이란 무엇인가요?

@"C:\Users\ana"처럼 @를 앞에 붙인 문자열 리터럴입니다. 이스케이프 시퀀스가 처리되지 않으므로 백슬래시는 그냥 백슬래시이고, 그래서 Windows 경로와 정규식에 자연스럽게 쓰입니다. 그 안의 유일한 이스케이프는 큰따옴표를 뜻하는 ""입니다.

C#에서 string과 String의 차이는 무엇인가요?

없습니다. int가 System.Int32의 별칭인 것처럼 string은 .NET 타입 System.String의 C# 키워드 별칭입니다. 관례상 선언에는 string을, 정적 호출에는 string.IsNullOrEmpty(...)를 쓰지만 둘은 완전히 같은 코드로 컴파일됩니다.

C#은 어떤 이스케이프 문자를 지원하나요?

\n 줄바꿈, \r 캐리지 리턴, \t 탭, \\ 백슬래시, \" 큰따옴표, \' 작은따옴표, \0 널 문자, \uXXXX 16진 코드로 지정하는 UTF-16 문자, \U0001F600 8자리 코드로 지정하는 문자(서로게이트 쌍이 됩니다), \a 경고음, \b 백스페이스, \f 폼 피드, \v 수직 탭, \e(C# 13) 이스케이프입니다. \d 같은 알 수 없는 시퀀스는 컴파일 오류(CS1009)이므로, 정규식은 보통 축자 문자열로 씁니다.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기