Silverlight를 설치하려면 여기를 클릭합니다.*
Korea 대한민국변경|Microsoft 전체 사이트
MSDN
|개발자 센터
MSDN 홈 > MSDN 칼럼 > Dr.GUI > Dr. GUI .NET #5 : .NET Framework의 문자열

Dr. GUI .NET #5

.NET Framework의 문자열

목차

이제까지 설명했던 내용 및 본 기사에서 설명할 내용
문자열
System.String 클래스
C#의 문자열
Visual Basic .NET의 문자열
표준 .NET Framework API가 있는 문자열
StringBuilder
System.Text 인코더 및 디코더
정규식
시도해 봅시다.
본 기사의 주제와 앞으로 다루게 될 주제

분명하게 말하라! 원본을 사용하라!

이 기사에는 영문 사이트에 대한 링크가 포함되어 있습니다. 이 기사에 대한 의견이 있는 경우에는 Dr. GUI .NET message board  에 의견을 남겨 주십시오.

그리고 Microsoft ASP.NET applications, with source code  로 실행되는 예제를 확인해 보십시오.

이제까지 설명했던 내용 및 본 기사에서 설명할 내용

지난 기사  에서 모든 .NET 클래스의 기원인 System.Object에 대해 설명했습니다. 또한 메모리 할당 및 가비지 수집, 그리고 .NET Framework에서 동적 형식 시스템이 어떻게 작동하는지에 대해서도 설명했습니다.

이번에는 .NET 런타임의 문자열에 대해 이야기하려고 합니다.

문자열

String(또는, 보다 구체적으로 System.String)은 .NET Framework의 문자열 리터럴 등의 문자열 형식입니다. .NET Framework에서 문자열에는 0 또는 그 이상의 16비트(2바이트) 유니코드 문자가 포함됩니다.

문자열은 변경할 수 없음

.NET Framework에서 익숙해지기 어려운 점은 String 개체를 변경할 수 없다는 것인데, 이것은 일단 개체가 만들어진 다음에는 값을 변경할 수 없다는 것을 의미합니다. 그러나 문자열에 대한 참조가 없을 경우 문자열 참조를 다시 할당하여 다른 문자열을 참조하도록 함으로써 가비지 수집에 대한 첫 번째 문자열을 제거할 수 있습니다.

문자열을 조작하는 String 메서드는 현재 문자열을 변경하지 않는 대신 새 문자열을 작성하여 반환합니다. 한 문자라도 변경하고 삽입하거나 삭제하면 새 문자열이 만들어지고 이전 것은 버려집니다.

반복적으로 문자열을 만들고 버리는 과정은 시간이 걸릴 수 있습니다. 그러나 문자열을 변경할 수 없도록 만드는 것은 변경할 수 없는 개체에 대한 소유권, 별칭 및 스레딩 문제가 훨씬 간단해 지므로 장점이 많습니다. 예를 들어, 문자열은 수정할 수 없으므로 문자열을 수정하면서 다른 스레드를 망칠 가능성도 없게 되므로 다중 스레드 프로그래밍에서 문자열은 언제나 안전합니다.

구조에 대한 StringBuilder

StringBuilder를 입력합니다. StringBuilder 개체는 문자열이 아니지만 16비트 유니코드 문자로 된 문자열을 조작하는 데 사용됩니다. 이 개체에는 버퍼가 들어 있으며, 일반적으로 문자열(보통 해당 문자열보다 큰)로 초기화됩니다. 버퍼의 문자는 새 버퍼를 작성하지 않고도 적절하게 조작될 수 있습니다(문자 삽입, 첨부, 제거 및 대체 가능). 물론, 원본 버퍼를 초과할 만큼 충분한 문자를 삽입하면 버퍼가 새로 만들어집니다. 문자 조작이 끝나면 StringBuilderToString 메서드를 사용하여 버퍼에서 완료된 문자열을 추출합니다. 대부분 StringBuilder.ToString은 복사본 작업을 일으키지 않고 작동되므로 매우 효율적입니다.

문자열 및 StringBuilder 인덱싱

두 형식에 모두 Char 유형의 유니코드 문자가 있으므로 지정한 인덱스에서 단일 Char를 반환하는 Chars라는 인덱서를 지원합니다. C#을 사용하는 경우 배열 아래 첨자처럼 이 인덱서에 액세스할 수 있습니다.

String은 변경할 수 없으므로 인덱서는 읽기 전용입니다. 물론 StringBuilder 인덱서가 읽기/쓰기용이므로 문자를 볼 수도 있고, 변경할 수도 있습니다.

System.String 클래스

System.String은 봉인된 클래스로 여기에서 상속할 수 없음을 의미하며, 또한 문자열 처리를 빠르게 하기 위해 시스템에서 특정 최적화 작업을 할 수 있음을 의미합니다.

대부분의 .NET 언어에는 문자열에 대한 기본 제공 지원이 있습니다. 예를 들어, .NET 언어는 일반적으로 문자열 리터럴 및 연결과 같은 작업을 지원합니다. 그러나 해당 구문은 언어에 따라 달라집니다.

C#의 문자열

C#의 문자열 리터럴

C#은 "일반" 문자열 리터럴과 "verbatim" 문자열 리터럴 등 두 가지 형식의 문자열 리터럴을 지원합니다.

일반 문자열 리터럴은 C 및 C++의 문자열 리터럴과 유사하여 인용 부호로 구분되고, 이스케이프 시퀀스를 포함하여 다양한 제어 문자 및 유니코드 문자를 나타낼 수 있습니다. 새 줄로 확장되지 않을 수도 있으나 인접한 문자열 리터럴은 컴파일 시 + 연산자로 연결될 수 있습니다. 모든 이스케이프 시퀀스는 백슬래시("\")로 시작하며 다음 표에 나열됩니다.

표 1. C# 문자열 리터럴 이스케이프 시퀀스

이스케이프 시퀀스 설명
\t 탭(유니코드 0x0009)
\r 캐리지 리턴(0x000d).
\n 줄 바꿈 문자(줄 바꿈)(0x000a)
\v 세로 탭(0x000b)
\a 경고(0x0007)
\b 백스페이스(0x0008)
\f 용지 공급(0x000c)
\0 Null(0x0000)
\\ 백슬래시(0x005c)
\' 작은따옴표(0x0027)
\" 큰따옴표(0x0022)
\xD 자릿수가 여러 가지인 16진수 문자 코드
\uABCD 유니코드 문자 0xABCD(A, B, C 및 D가 유효한 16진수 0-9, a-f, A-F일 경우 u 또는 U 허용)

이러한 모든 이스케이프 시퀀스는 모든 일반 문자열 리터럴에서 또는 모든 문자 리터럴(예: '\t')에서 사용할 수 있습니다. 또한, 유니코드 이스케이프 시퀀스는 식별자에서 사용될 수 있으므로"if (a\U0066b == true)"는 "if (afb == true)"와 같습니다(Unicode 0x0066dms가 "f"이므로). 이렇게 하면 해당 문자가 키보드에 없거나 편집자가 사용하는 글꼴로 표시할 수 없는 경우에도 모든 유효한 유니코드 문자를 사용하여 식별자를 작성할 수 있습니다.

Verbatim 문자열 리터럴은 @"로 시작하고 일치하는 따옴표로 끝납니다. Verbatim 문자열 리터럴에는 이스케이프 시퀀스가 없습니다. 그러므로

@"\\machine\share\path1\path2\file.ext"

"\\\\machine\\share\\path1\\path2\\file.ext"

와 같지만 더 간단하고 오류가 발생할 확률이 적습니다. 또한 Verbatim 문자열 리터럴은 줄 바꿈 위로 확장될 수 있습니다. 그런 경우, 따옴표 사이에 공백 문자가 포함됩니다.

@"First \t line
   tabbed second line"
// "First \\t line\r\n\ttabbed second line"과 동일
참고   두 번째 문자열에 "\r"이 필요한지 여부는 편집자에 따라 다릅니다. Microsoft Visual Studio .NET에서는 각 줄의 끝에서 캐리지 리턴/줄 바꿈 쌍을 사용하므로 Visual Studio .NET 편집기를 사용하여 파일을 작성하는 경우 둘 다 필요합니다. 다른 편집기에서는 줄 바꿈 문자(ASCII 코드 10 또는 줄 바꿈)만으로 줄이 끝날 수 있습니다.

verbatim 문자열 리터럴에 대한 "이스케이프 시퀀스 없음" 규칙의 유일한 예외는 verbatim 문자열 안에 큰따옴표를 이중으로 넣을 수 있다는 점입니다.

@"This is a ""quote"" from me."
// "This is a \"quote\" from me."와 동일

C#의 문자열 작업

C#은 해당 언어에서 다음 문자열 작업을 지원합니다.

  • 개별 문자를 읽을 수 있도록(쓰지는 않음) 문자열 인덱싱(예: s[i])
  • 두 문자열을 + 연산자와 연결(예: s + t) 문자열 이외에는 s 또는 t 중 하나가 형식이 될 수 있습니다. 이 중 하나가 형식인 경우 여기에 ToString을 호출하여 문자열로 변환할 수 있습니다. + 연산자는 String 클래스의 구성원으로서가 아니라 C# 언어의 일부로 구현됩니다. 피연산자 중 하나가 null이면 빈 문자열 ""와는 반대로 빈 문자열로 변환될 수 있습니다. 컴파일 시에 작업이 될 수 있는 경우에는 그렇게 합니다.
  • 같음 및 같지 않음(예: s == ts != t) 이러한 연산자는 String 클래스의 일부이므로 오버로드된 연산자를 지원하는 모든 언어에서 사용할 수 있습니다. 연산자 구문 대신 구성원 이름 op_Equalityop_Inequality를 사용하여 Microsoft Visual Basic .NET과 같은 오버로드된 연산자를 지원하지 않는 언어로도 사용할 수 있습니다. 이러한 연산자는 String.Equals를 호출하며, 이것은 culture를 인식하여 비교하는 것이 아니라 두 문자열의 문자를 이진 비교합니다.

가능한 경우 컴파일 시에 연결됩니다. 또한 모든 개체를 문자열로 연결할 수 있으며, 이를 통해 개체의 ToString 메서드에서 반환값이 연결됩니다. 예를 들어, 다음은 모두 유효합니다.

string s0 = " Hello ";
string s1 = s0 + 5;   // " Hello 5"
string s2 = 6.3 + s1;   // "6.3 Hello 5"
string ret = String.Format("s0: {0}\ns1: {1}\ns2: {2}", s0, s1, s2);

또한 문자열은 변경할 수 없으므로 컴파일러 및 런타임은 중복 문자열 리터럴을 병합하여 프로그램의 각 리터럴에 복사본이 하나만 있도록 합니다.

Visual Basic .NET의 문자열

Visual Basic .NET의 문자열 리터럴

Visual Basic .NET 문자열 리터럴은 매우 간단합니다. 이것은 큰따옴표, 그 다음 유니코드 문자 집합, 그 다음 닫는 큰따옴표로 이루어집니다. 문자열 안에 큰따옴표를 포함시키려면 다음에서처럼 큰따옴표를 두 번 사용합니다.

"This prints ""Hello, world!"" on the screen"

큰따옴표를 두 번 사용하는 것 이외에는 Visual Basic .NET 문자열이나 문자 리터럴에 대한 이스케이프 시퀀스 메커니즘이 없습니다. 이것은 Visual Basic .NET 문자열 리터럴에 줄 끝(EOL) 문자를 포함시킬 수 없다는 것을 제외하고는 C# verbatim 문자열 리터럴과 비슷합니다. 이 문자열 리터럴은 한 줄에 들어 있어야 합니다. 줄 바꿈 문자처럼 Visual Basic .NET 프로그램에서 나타낼 수 없는 문자를 포함시켜야 하는 경우 Chr 또는 ChrW 함수를 사용하여 해당 코드에서 문자를 만든 다음 문자열에 연결합니다. 캐리지 리턴(Chr(13))을 사용하면 새 줄로 이동하지 않으므로 화면에서 두 줄이 겹쳐보일 수 있습니다. 캐리지 리턴과 줄 바꿈을 모두 사용하려면 Environment.NewLine 속성을 사용할 수 있습니다.

"First line" & Chr(10) & "Second line" ' LF 전용
"First line" & Environment.NewLine & "Second line" ' CR/LF

Visual Basic .NET의 문자열 작업

Visual Basic .NET에는 모든 C#의 문자열 연산자와 C#에 없는 몇 가지 연산자가 들어 있습니다. Visual Basic .NET의 연산자는 다음과 같습니다.

  • + 연산자만을 사용하여 StringString에 연결(예: s + t). 이 연산자는 피연산자가 모두 문자열인 경우에만 문자열을 연결합니다. 두 피연산자 중 하나가 문자열이 아니면 Visual Basic .NET에서는 문자열을 Double로 변환하려고 시도하고 덧셈을 실행합니다. 이때문에 아래에 설명한 것처럼 & 연산자를 사용하여 연결하는 것이 더 좋습니다.
  • & 연산자를 사용하여 두 개체 연결(예: s & "There"). & 연산자의 피연산자가 문자열이 아니면 둘 다 문자열로 변환됩니다. 이것은 x & y의 구문에서처럼 두 숫자 xy의 문자열 표현을 연결할 수 있다는 의미입니다. 이 연산자는 애매하지 않기 때문에 연결에 많이 사용됩니다. 이 연산자는 항상 연결을 수행합니다.
  • 비교의 전체 집합: =, <>, >, <, >=, <=. 이것은 컴파일 옵션 및 Option Compare 문(있을 경우)에 따라 이진 비교 또는 텍스트(culture 구분) 비교를 실행합니다. 또한 StrCompOption Compare를 사용하여 비교 형식을 설정하거나 사용할 비교 메서드를 표시하는 매개 변수를 전달하여 문자열 비교를 실행합니다.
  • Like 연산자를 사용하면 문자열이 단순화된 정규식 언어로 설명된 패턴과 일치하는지 여부를 결정할 수 있습니다. System.Text.RegularExpressions.RegEx에서 지원하는 정규식 언어에는 보다 많은 기능이 있으므로 해당 API를 대신 사용할 수 있습니다.
  • Visual Basic .NET에는 배열 아래 첨자 표기법을 사용하여 문자열의 개별 문자에 액세스할 수 있도록 하는 인덱서가 없지만 Chars 속성을 사용하여 문자열의 개별 문자를 얻고 StringBuilder의 개별 문자를 얻고 설정할 수 있습니다.

Visual Basic .NET에만 있는 문자열 함수 및 문

Visual Basic .NET 언어에서 제공되는 연산자 이외에도 Visual Basic .NET에 대해 고유한 문자열을 조작하기 위한 함수 및 문으로 이루어진 그룹이 있으며, 이것은 표준 .NET Framework 라이브러리에는 있지 않습니다.

Visual Basic .NET 프로그래머의 경우 Visual Basic 전용 버전이나 표준 .NET Framework 버전 중에서 어느 것을 사용할지 선택할 수 있습니다. 그러나 Framework에서 제공되지 않는 함수를 Visual Basic이 제공하는 몇 가지 영역이 있습니다. Dr. GUI는 표준 .NET Framework API를 따르는 것이 편리하다면 계속해서 이것을 사용하도록 권장합니다. 이렇게 하면 나중에 다른 언어로 사용할 수 있도록 다양한 기술을 개발하는 데 도움이 됩니다.

반면 Visual Basic 전용 버전의 구문 및 동작은 이전 버전의 Visual Basic 구문 및 동작과 유사하므로 Visual Basic 전용 버전은 이전 Visual Basic 코드를 Visual Basic .NET으로 포팅하는 데 아주 편리할 수 있습니다.

부분 문자열

BASIC을 프로그램해 본 경험이 있다면 문자열의 왼쪽, 오른쪽 및 가운데에서 문자를 추출하는 데에 Left, RightMid 함수를 사용할 수 있으며 할당 연산자의 왼쪽에서 문자열 가운데 있는 문자를 변경하는 데 Mid를 사용할 수 있다는 것도 기억할 것입니다.

여러분이 기억하는 대로 이러한 모든 기능이 Visual Basic .NET에 있습니다. 아주 중요한 사실 하나는 문자를 시작하기 위해 Mid에 사용된 인덱스는 .NET에서 다른 것과 마찬가지로 0을 기반으로 하는 것이 아니라 1을 기반으로 한다는 점입니다. 이것은 Mid가 BASIC에서 MID$(으)로 시작한 이후로 1을 기반으로 하기 때문입니다.

Dr. GUI가 새 코드에서 절대로 Mid를 사용하지 않도록 권하는 것은 아주 중대한 문제입니다. 차라리 Mid를 이미 작동하고 있는 포팅하려는 코드에 대해 사용하도록 남겨두고 디버깅할 때 머리를 쥐어뜯을 준비를 하는 것이 낫습니다. 1을 기반으로 하는 계산과 0을 기반으로 하는 계산을 계속 하면 머리가 이상해질 것입니다.

String.SubString 메서드는 Left 함수와 Mid 함수에 대해 대체할 수 있는 오버로드를 제공합니다. Substring은 시작 위치를 0으로 하고 Mid는 시작 위치를 1로 하므로 Left에 대해서는 str.Substring(0, len)을 사용하고, Mid에는 str.SubString(start, len)을 사용하여 시작 위치를 1씩 조절해야 합니다.

Right의 경우는 시작 위치를 계산해야 하기 때문에 좀 더 어렵습니다. 예를 들면,

Dim s As String = "Hello, world!"
Dim t1 As String = s.Substring(s.Length - subLen)
      ' 아래와 동일
Dim t2 As String = Right(s, subLen)
Dim ret As String = String.Format("s0: {0}\nt1: {1}\nt2: {2}", s, t1, t2)
ret = ret.Replace("\n", Environment.NewLine)

여기서 Dr. GUI가 보여준 작은 속임수에 유의하십시오. Dr. GUI는 이스케이프 시퀀스("\n")를 무조건 포함시켜 Visual Basic .NET에는 줄 바꿈 문자에 대한 이스케이프 시퀀스가 없음을 기정사실화한 다음 이스케이프 시퀀스가 발생할 때마다 문자열을 반환하기 바로 전에 두 글자로 된 Environment.NewLine 문자열("\r\n")로 대체했습니다. 출력 문자열을 C# 버전에서와 똑같이 만들려면 "\n"을 Environment.NewLine 대신 Chr(10)으로 대체해야 합니다.

문자열에서 문자를 대체하는 Mid 문은 대체하기가 좀 더 복잡합니다. String.Remove를 사용하여 대체될 문자를 제거하고 String.Insert를 사용하여 새 문자를 삽입할 수 있지만, 이 경우 두 개의 문자열을 새로 만들어야 합니다. 다음과 같이 수정할 문자열의 첫 번째 부분 문자열에서 StringBuilder를 만들고 이에 대한 대체를 추가하며 여기에 원본 문자열의 끝부분을 추가하는 것이 더 효율적입니다.

Dim s As String = "123456xxx0"
' 부분 문자열은 0부터 시작
Dim sb As StringBuilder = New StringBuilder(s.Substring(0, 6))
sb.Append("789")
sb.Append(s.Substring(9, 1)) ' 0부터 시작, 10번째 문자
s = sb.ToString()
' Mid(s, 7, 3) = "789"와 동일 ' 1부터 시작
Dim t As String = "123456xxx0"
Mid(t, 7, 3) = "789"
Dim ret As String = String.Format("s: {0}\nt: {1}", s, t)
ret = ret.Replace("\n", Environment.NewLine)

매우 이상한 함수 하나

Visual Basic .NET에는 매우 이상한 함수 StrConv가 들어 있습니다. 이 함수는 비트 집합으로 지정된 다양한 변환을 사용하여 문자열을 다른 문자열로 변환합니다. 이 함수는 파일 시스템 규칙이나 culture 구분 규칙을 사용하여 대문자 또는 소문자로 변환합니다. 예를 들어, 각 단어의 첫 글자가 소문자이면 대문자로 변환하고 적절한 동아시아 언어(예: 한국어, 일본어, 중국어)를 사용하는 경우 의미가 통하도록 만드는 몇 가지를 변환하며(실제로는 변환해야만 작동함), 전자/반자로 변환할 뿐만 아니라 가타카나에서 히라가나로, 히라가나에서 가타카나로(일본어의 경우만) 변환합니다. 중국어의 간체와 번체 사이에서도 변환할 수 있겠지만 이 기능은 제대로 작동하지 않는다고 알려져 있으므로 Dr. GUI에서는 이 기능을 사용하지 않는 것이 좋습니다.

.NET Framework API에서는 대부분의 이러한 변환에 해당하는 기능이 없습니다. 그러나 Windows LCMapString API를 사용하여 변환할 수는 있습니다. Visual Basic이 아닌 .NET 언어에서 이 작업을 하려면 플랫폼 API interop을 사용하여 LCMapString을 호출합니다(Visual Basic에서의 작업과 동일).

.NET Framework 기능과 일치하는 함수

.NET Framework 기능과 일치하는 Visual Basic .NET 문자열 함수에는 여러 가지가 있습니다. 다음 표는 Visual Basic .NET 함수 및 이와 가장 유사한 .NET Framework 함수를 나열하고 있습니다. 경우에 따라 기능이 정확하게 일치하지 않을 수도 있습니다. 또한 많은 경우에 .NET Framework 버전에는 추가 기능을 제공하는 추가 오버로드가 들어 있습니다. 이 작업을 효율적으로 하려면 설명서를 유의해서 읽어야 합니다. 아래 표를 사용하여 읽어들이는 데 사용할 적절한 메서드를 찾습니다.

표 2. Visual Basic별 문자열 함수 및 가장 가까운 표준 .NET Framework 함수

Visual Basic .NET 함수 의미 가장 유사한 .NET Framework 함수
StrReverse 문자열을 반대 방향으로 바꿉니다. 없음—문자를 제자리에서 바꿔 StringBuilder를 사용하고 반대 방향으로 루핑합니다.
InStr, InStrRev 부분 문자열의 첫/마지막 인덱스를 찾습니다. IndexOf, LastIndexOf
LCase, UCase 소문자/대문자로 변환합니다. ToLower, ToUpper
Format, FormatCurrency, FormatNumber, FormatPercent 문자열 표현에 대해 culture를 구분하는 값 서식입니다. obj.ToString 또는 String.Format
Str, Val 숫자를 문자열로, 문자열을 숫자로 변환합니다. culture를 구분하지 않습니다. 위의 함수 중 하나에는 지정된 CultureInfo.Invariant가 있습니다.
Trim, LTrim, RTrim(공백에만) 문자열의 끝에서 공백을 자릅니다. String.Trim, String.TrimStart, String.TrimEnd(공백 옆의 문자를 자를 수 있음)
Len 문자열 길이를 반환합니다. String.Length
Space, StrDup 반복된 공백 또는 기타 문자가 있는 문자열을 만듭니다. 문자를 취하고 계산을 하는 String 생성자입니다.
Replace 문자열 안의 부분 문자열을 대체합니다. String 또는 StringBuilder에서 대체합니다.
Split, Join 지정된 구분자에서 문자열을 잘라 문자열 배열을 만들거나 문자열 배열에서 구분된 문자열을 만듭니다. String.Split, String.Join
Filter 부분 문자열을 포함하는 다른 배열에서 문자열 배열을 만듭니다. 해당 사항 없습니다. 동적으로 확장 가능한 ArrayList에 문자열을 넣어 각 루프에 대해 기록합니다.
AscW, ChrW 유니코드 정수를 단일 문자 문자열로, 단일 문자 문자열을 유니코드 정수로 변환합니다. char에서 정수 형식으로, 정수 형식에서 char로 캐스팅합니다.
Asc, Chr 코드 페이지 정수를 단일 문자 문자열로, 단일 문자 문자열을 코드 페이지 정수로 변환합니다. 인코딩을 사용합니다(나중에 설명함).
CStr 문자열로 변환합니다. obj.ToString

표준 .NET Framework API가 있는 문자열

문자열 개체 만들기

두 가지 언어로 new/New 문이 있는 String 개체를 만들 수 있습니다. 대부분의 CLI 규격 String 생성자는 문자 및 정수 또는 문자 배열 중 어느 것도 취하지 않습니다. 그러므로 문자 배열을 가지고 있지 않은 경우에는 다른 메서드를 사용하여 문자열을 작성합니다. 문자열을 취하는 생성자는 없으나 Char 및 정수 계산을 하는 생성자가 있습니다. 그 결과로 나온 문자열에는 계산에서 지정한 횟수만큼 반복된 문자가 있을 수 있습니다.

가장 일반적인 메서드는 문자열 리터럴로 초기화되며 다른 문자열에서 값을 할당합니다.

[C#]
string s = "Hello, world!";
string t = s;   // 복사본 없음; s 및 t는 동일한 문자열 참조
string ret = String.Format("s and t refer to same: {0}",
   Object.ReferenceEquals(s, t));

[Visual Basic .NET]
Dim s as string = "Hello, world"
Dim t as string = s ' 복사본 없음; s 및 t는 동일한 문자열 참조
Dim ret as string = String.Format("s and t refer to same: {0}", s Is t)

복제가 복제가 아닌 경우?

그러나 각 문자열에 같은 값이 있는 별도의 두 문자열이 필요한 경우라면? 글쎄, 아마 이런 경우를 원하지 않을 것입니다. 메모리를 왜 낭비합니까? 문자열을 변경할 수 없으므로 같은 값이 있는 별도의 두 문자열이 있어도 별로 의미가 없습니다.

그러므로 StringIClonable을 구현해도 String.Clone은 문자열을 복제하지 않고 단순히 같은 문자열에 대한 참조를 반환합니다.

그러나 모든 것을 잃는 것은 아닙니다. 문자열의 두 번째 복사본이 꼭 필요한 경우 정적 메서드 Copy를 사용할 수 있습니다. 참조 균일성은 두 가지 방법으로 확인할 수 있습니다. 첫 번째는 Object.ReferenceEquals를 호출하는 것이고 두 번째는 C#에서 균일성을 확인하기 전에 개체에 대한 참조를 캐스팅하고 Visual Basic에서 Is 연산자를 사용하는 것입니다.

[C#]
string s = "Hello";
string t = (string)s.Clone();   // 복사본 없음; s 및 t는 동일한 문자열 참조
string u = String.Copy(s); // 복사본 작성; s 및 u는 다른 개체 참조
string ret = String.Format("s same as t: {0}, s same as u: {1}",
   Object.ReferenceEquals(s, t), (object)s == (object)u);

[Visual Basic .NET]
Dim s as string = "Hello"
Dim t as string = CStr(s.Clone()) ' 복사본 없음, s 및 t는 동일한 문자열 참조
Dim u as string = String.Copy(s)  ' 복사본 작성, s 및 u는 두 개체 참조
Dim ret as string = String.Format("s same as t: {0}, s same as u: {1}", _
       Object.ReferenceEquals(s, t), s Is u)

또한 String.CopyTo 메서드를 사용하여 문자열 전체나 일부를 문자 배열로 복사할 수 있습니다. 문자 배열을 매개 변수로 취하는 문자열 생성자를 사용하여 문자 배열이나 그 부분에서 문자열을 만듭니다.

기타 인터페이스, 플러스 속성 및 필드

앞에서 보았듯이, 타당성 있기는 하지만 약간 이상한 방식으로 StringICloneable을 구현합니다. 또한 문자열은 IComparable을 구현합니다. 이것은 IComparableCompareTo 메서드(나중에 자세히 설명)를 사용하여 두 문자열을 비교할 수 있음을 의미합니다. StringIConvertable을 구현하기는 하지만, Convert 클래스의 메서드를 사용하여 문자열을 To 메서드를 사용하는 모든 기본 제공 값 형식으로 변환해야 합니다.

또한 String에는 몇 가지 재미있는 속성이 있습니다. 문자열의 Length 속성(읽기 전용)에 액세스하여 모든 문자열의 길이(문자 수, 바이트가 아님)를 알 수 있습니다. C# 인덱서로 매핑된 읽기 전용인 인덱서 속성 Chars를 통해 한 번에 한 문자씩 문자열에 액세스할 수 있습니다.

[C#]
string s = "Hello, world!";
StringBuilder sb = new StringBuilder(String.Format(
"Length of \"Hello, world!\" is {0}\n", s.Length)); // 13
for (int i = 0; i < s.Length; i++)
   sb.AppendFormat("{0} ", s[i]);

[Visual Basic .NET]
Dim s as string = "Hello, world!"
Dim sb as StringBuilder = new StringBuilder( _
String.Format("Length of ""Hello, world!"" is {0}", s.Length)) ' 13
sb.Append(Environment.NewLine)
Dim i as Integer
For i = 0 to s.Length - 1
   sb.AppendFormat("{0} ", s.Chars(i))
Next

Visual Basic .NET에서도 문자열 문자가 0부터 시작하여 인덱스되었으므로 루프를 적절하게 기록하도록 유의해야 합니다(C#에서는 같은 문제가 <= 연산자가 아닌 < 연산자를 사용하여 처리됨).

빈 문자열이 들어 있는 Empty라고 하는 재미있는 정적 필드가 있습니다. 이것은 언어에 관계없이 빈 문자열을 표현하는 방법입니다("").

문자열 균일성/비교 메서드

두 가지 문자열을 비교하는 방법에는 여러 가지가 있습니다. 균일성과 비균일성에 대해 가장 큰 차이점은 물론 비교가 참조에 의한 것인지(두 문자열이 같은 개체를 가리킴), 또는 값에 의한 것인지(두 문자열에 같은 문자가 들어 있음) 하는 문제입니다.

균일성 및 관계형 비교의 경우, 가장 중요한 차이점은 현재 culture의 대조 순서를 사용할지 또는 문자열의 각 문자에 대해 원시 서수 값을 사용할지 하는 문제입니다. 사소한 차이점으로는 비교가 대/소문자를 구분하는지 여부입니다. 비교의 기본값은 문자열이 실행 중인 스레드의 현재 culture를 사용하고 대/소문자를 구분하는 것입니다. 다음은 일반적으로 사용자가 원하는 것입니다.

== 연산자는 culture를 구분하고 대/소문자를 구분하는 비교를 수행하는 String.Equals에 대한 호출을 생성합니다. C#에서 참조 비교를 수행하려면 개체에 대한 두 가지 문자열 참조를 캐스팅하거나 Object.ReferenceEquals를 사용합니다. Visual Basic .NET에서는 아래와 같이 Is 연산자(Visual Basic에서)를 사용하거나 Object.ReferenceEquals를 사용합니다. 두 언어 중 하나에서 Object.ReferenceEquals를 사용할 수 있습니다.

[C#]
      string s = "Hello", t = "there";
      bool valueComp = (s == t); // 값 비교
      bool refComp1 = ((Object)s == (Object)t); // 참조 비교
      bool refComp2 = Object.ReferenceEquals(s, t); // 참조 비교
      string ret = String.Format("s == t: {0}, " +
         "(object)s == (object)t: {1}, ObjectRefEq(s, t): {2}",
         valueComp, refComp1, refComp2);

[Visual Basic .NET]
Dim s as string = "Hello"
Dim t as string = "there"
Dim valueComp as Boolean = s = t ' 값 비교
Dim refComp1 as Boolean = s Is t ' 참조 비교
Dim refComp2 as Boolean  = Object.ReferenceEquals(s, t) ' 참조 비교
Dim ret as string = _
String.Format("s = t: {0}, s Is t: {1}, ObRefEq(s, t): {2}", _
   valueComp, refComp1, refComp2)

Visual Basic .NET의 같음, 같지 않음 및 비교 연산자(=, <>, >, <, >=, <=)는 컴파일러 옵션 및 Option Compare 문에 따라 서수 비교 또는 culture 구분 비교 중 하나를 수행합니다. 참조 비교를 수행하려면 Is 연산자를 사용합니다. 또한 Visual Basic .NET에는 단순하게 패턴을 일치시키는 문자열 비교에 대한 Like 연산자가 있습니다.

Equals 메서드를 사용하면 몇 가지 좋은 점이 있습니다. 인스턴스 메서드에는 두 가지가 있습니다. 하나는 String을 매개 변수로 취하고, 다른 하나는 Object(String을 참조해야 하는)를 취합니다. 두 개의 문자열을 취하는 Equals의 정적 버전도 있습니다. 원래 Object에서 정의된 Object를 취하는 버전은 재정의되고, 문자열을 취하는 버전은 변환이 필요없으므로 더 빠릅니다. 정적 버전은 예외를 throw하지 않고 null/Nothing이 전달되는 것을 처리할 수 있습니다.

비교에 대해서는 Compare, CompareOrdinalCompareTo의 세 가지 메서드가 있습니다. 이러한 모든 메서드는 첫 번째 문자열이 두 번째 문자열보다 더 작으면 음수를 반환하고, 값이 같으면 0을 반환하며, 첫 번째 문자열이 두 번째 문자열보다 더 크면 양수를 반환합니다.

Compare는 오버로드된 정적 메서드 집합으로 culture 구분 비교를 하면 기본값으로 대/소문자를 구분합니다. 각 오버로드는 적어도 두 문자열을 비교합니다. 또한 대/소문자 구분 여부를 지정하는 Boolean 및 비교할 부분 문자열의 길이와 인덱스를 지정하는(전체 문자열을 비교하는 대신) Int32를 취하는 오버로드도 있습니다.

CompareOrdinal은 오버로드된 정적 메서드의 쌍으로 두 문자열 또는 두 문자열 안의 부분 문자열에 대한 서수 비교를 실행합니다.

CompareToIComparable을 구현하는 인스턴스 메서드입니다. 이 메서드는 culture 구분 및 대/소문자 구분 비교를 사용하여 매개 변수로 전달된 개체나 문자열이 있는 현재 문자열을 비교합니다.

문자열 검색: EndsWith/StartsWith/IndexOf/LastIndexOf/Substring

문자열에 들어 있는 내용을 알아내는 메서드에는 여러 가지가 있습니다. EndsWithStartsWith는 현재 문자열이 지정된 문자열로 끝나거나 시작하면 true를 반환하고, 그렇지 않으면 false를 반환합니다.

IndexOfLastIndexOf에는 오버로드가 많이 있습니다. 각각은 문자열 또는 문자 배열이 발생하는 현재 문자열 또는 부분 문자열에서 첫/마지막 위치를 반환합니다.

Substring은 이전의 GW-BASIC MID$ 함수 및 Visual Basic .NET Mid 함수와 비슷합니다. 단, 해당 문자열의 인덱스가 Mid/MID$에서처럼 1에서 시작하는 대신 0에서 시작한다는 점이 다릅니다. 오버로드에는 두 가지가 있습니다. 하나는 지정된 인덱스에서 문자열 끝까지 부분 문자열을 포함하는 새 문자열을 만들고 반환합니다. 다른 하나는 지정된 인덱스에서 시작하는 지정된 길이의 부분 문자열을 포함하는 새 문자열을 만들고 반환합니다.

서식

String 클래스에는 정적 Format 메서드 오버로드의 패밀리가 있습니다. 모든 오버로드는 Console.WriteLine에 대한 호출에서 사용했던 것과 같은 서식 기능을 제공합니다. 이러한 오버로드는 남은 매개 변수의 문자열 표현으로 대체된 형식 지정자가 있는 새로운 문자열을 만들고 반환합니다. 예를 들면, 다음을 사용할 수 있습니다.

[C#]
string ret = String.Format("The value is {0}", 5);
// "값이 5입니다."(따옴표 없이)

[Visual Basic .NET]
Dim ret as string = String.Format("The value is {0}", 5)
' "값이 5입니다."(따옴표 없이)

데이터를 포맷하는 데에는 여러 가지 방법이 있으며, culture 인식에 대한 많은 문제가 있습니다. 유감스럽게도 이번에는 그러한 문제까지 자세히 다룰 시간이 없습니다. 일반적으로 .NET Framework는 사용자가 CultureInfo.InvariantCulture를 서식 메서드로 전달하지 않는 한 culture를 인식하는 변환 및 서식 작업을 실행합니다. Visual Basic .NET 기본 제공 메서드는 종종 고정 culture를 기본값으로 설정하므로 유의하십시오.

구문 분석

변환하려는 클래스의 Parse 메서드를 사용하여 문자열에서 다른 많은 형식으로 변환할 수 있습니다. 예를 들어, 정수로 변환하려면 Int32.Parse 메서드를 사용할 수 있습니다. Convert 클래스에서 메서드를 사용할 수도 있고, 경우에 따라 개체(C#에서)를 캐스트할 수도 있으며, Visual Basic의 CType 또는 CStr 함수를 사용하는 등 변환에는 여러 가지 방법이 있습니다.

패딩 및 지우기

PadLeftPadRight라고 하는 공백(또는 원하는 문자)으로 문자열의 왼쪽이나 오른쪽 부분을 패딩하는 메서드에는 여러 가지가 있습니다. 또한 문자열의 시작 및/또는 끝에서 공백이나 지정한 문자 집합을 잘라내는 메서드에는 여러 가지가 있습니다(TrimStart, TrimEnd, Trim). 이 메서드는 모두 새 문자열을 만들어 반환합니다.

Insert/Remove/Replace/Concat

이러한 메서드는 StringBuilder에 있는 것과 다소 유사하지만, StringBuilder에서보다 String에 있는 오버로드가 더 적습니다. 다음 항목에서 StringBuilder의 차이점에 대해 알아봅니다.

Insert는 지정한 위치에 삽입된 지정된 문자열로 새 문자열을 만듭니다. Remove는 지정된 위치에서 제거된 지정된 수의 문자로 새 문자열을 만듭니다. Replace는 다른 문자나 문자열로 대체된 지정된 문자나 문자열의 모든 항목으로 새 문자열을 만들고 반환합니다. 그리고 정적 메서드 Concat의 다양한 오버로드는 문자열 및/또는 메서드가 전달된 개체를 연결하여 새 문자열을 만들고 반환합니다.

Split/Join

SplitJoin은 강력한 메서드입니다. Join은 정적 메서드이며, 지정된 문자열을 구분자로 사용하여 메서드가 전달된 문자열 배열에서 문자열의 일부 또는 전체를 연결하여 만들어진 문자열을 반환합니다. Split은 지정된 구분자 문자 집합을 사용하여 새로 작성되고 반환된 문자열 배열로 문자열을 분할합니다.

변환

String에는 직접 액세스할 수 있는 변환 메서드가 포함되어 있지 않지만 Convert 클래스에는 여러 가지 static/Shared 변환 메서드가 들어 있으며, 이 메서드의 대부분은 일부 기본 제공 형식으로 변환되며 To의 형식입니다. 문자열에 대해 기본 제공 형식으로 변환하는 목록에는 ToBoolean, ToByte, ToChar, ToDecimal, ToDouble, ToInt16, ToInt32, ToInt64, ToSByte, ToSingle, ToString, ToUInt16, ToUInt32ToUInt64 등이 포함됩니다. DateTime 개체—ToDateTime—로 변환하는 메서드가 하나 있고 바이트 배열 및 기본 64인코드된 문자열(이진 데이터를 텍스트 프로토콜을 통해 전송하는 데 유용함) 간 변환하는 메서드가 여러 개 있습니다(FromBase64StringToBase64String).

String에는 문자 배열로 변환하는 ToCharArray 메서드가 포함되어 있습니다. 그리고 문자열을 대문자나 소문자로 변환하는 ToUpperToLower 메서드가 있습니다.

Intern/IsInterned

.NET 런타임은 응용 프로그램 도메인(프로세스와 약간 비슷함)에서 리터럴 문자열의 풀을 유지합니다. .NET 런타임이 프로그램 등의 어셈블리를 응용 프로그램 도메인으로 로드하는 경우 어셈블리의 문자열 리터럴을 문자열 리터럴의 응용 프로그램 도메인 풀로 병합하여 문자열 리터럴이 중복되는 것을 방지합니다. 문자열은 변경할 수 없으므로 프로그램의 결과를 변경하지 않고도 이 작업을 수행할 수 있습니다. 모든 문자열 리터럴이 억류되어 있다는 사실은 각 문자열 리터럴에 복사본이 하나뿐이므로 문자열 리터럴의 참조 비교를 올바르게 수행할 수 있다는 의미도 됩니다.

그러나 문자열을 새로 작성하는 String 메서드 중 하나를 통해서 또는 StringBuilder를 사용하여 문자열을 직접 빌드하는 경우 리터럴 풀(한 개 있다고 가정)에 같은 값이 있는 문자열과는 다른 문자열이 되므로 참조 비교에 실패하게 됩니다. 참조 비교에서는 주소만 비교하면 되기 때문에 값 비교보다 훨씬 더 빠르므로 큰 문제가 될 수 있습니다. 그러므로 빨리 실행하려는 코드에서 제대로 작동할 것이라고 확신한다면 참조 비교를 사용하십시오!

문자열을 리터럴 풀에 추가하려면, 문자열을 리터럴 풀에 추가하고(아직 없을 경우) 리터럴 풀 문자열에 참조를 반환하는 정적 메서드 Intern을 사용할 수 있습니다. 예를 들면,

[C#]
string s2 = new StringBuilder().Append("Foo").Append("Bar").ToString();
string s3 =String.Intern(s2);   // 리터럴 풀에 참조 반환
string s = "FooBar";            // 모두 리터럴 풀에 있었음
StringBuilder sb = new StringBuilder();
sb.Append(Object.ReferenceEquals(s2, s));   // 거짓: 다름
sb.Append(", ");
sb.Append(Object.ReferenceEquals(s3, s));   // 참: 동일

[Visual Basic .NET]
Dim s2 as string = New _
     StringBuilder().Append("Foo").Append("Bar").ToString()
Dim s3 as string = String.Intern(s2) ' 리터럴 풀에 참조 반환
Dim s as string = "FooBar"  ' 모두 리터럴 풀에 있었음
Dim sb as new StringBuilder()
sb.Append(s2 Is s) ' 거짓: 다름
sb.Append(", ")
sb.Append(s3 Is s) ' 참: 같음

또한 문자열이 true를 반환하는 정적 IsInterned 메서드와 함께 이미 풀에 있는지 확인할 수 있습니다.

GetHashCode

지난 기사  에서 Equals를 재정의하는 경우 GetHashCode도 재정의해야 한다는 것에 대해 설명했습니다. String에서 Equals가 재정의되고 GetHashCode도 재정의되면 해시 및 성능이 좋아집니다.

StringBuilder

String의 많은 메서드가 문자열을 새로 만들고 반환한다는 것을 발견했을 것입니다. 이미 추측했겠지만 많은 문자열을 할당하고 throw하면 비용이 많이 들 수 있습니다.

일반적으로 새 문자열을 만드는 것과 관련된 특정 문자열에서 한 문자열 작업만 수행하려는 경우 String에 적절한 메서드(또는 적절한 Visual Basic .NET 함수)를 사용하여 진행하십시오. 그러나 여러 개를 실행하려고 하고 필요한 작업이 System.Text.Stringbuilder에 있을 경우, 문자열에서 StringBuilder를 만들고 StringBuilder에서 여러 작업을 수행한 다음 StringBuilder에서 ToString을 호출하여 결과 문자열을 돌려받습니다. 이 작업이 모두 한 줄에서 시행된 앞의 예제를 참조하십시오.

StringBuilder에서 문자열을 빌드하고 조작하며 이것을 문자열로 변환하는 것은 아주 흔한 일입니다. ToString을 호출해도 실제로는 나중에 같은 StringBuilder 개체를 수정할 때까지 문자열을 복사하지 않습니다. 그러므로 이것은 아주 효과적입니다. StringBuilder를 사용하는 데 대한 오버헤드는 두 개가 아니라 하나의 복사본 작업입니다. 이것이 한 작업 규정을 둔 이유입니다. 두 개 이상의 작업에 대해서는 StringBuilder를 사용해야 합니다.

사용할 수 있는 오버로드가 String의 좀 더 제한된 오버로드보다 훨씬 사용하기 쉬운 경우 StringBuilder를 사용할 수도 있습니다.

StringBuilder를 사용하려면 프로그램 파일의 시작 부분에 System.Text 사용; (Visual Basic의 System.Text가져오기)가 있어야 합니다.

StringBuilder에는 문자열의 개체를 초기화하고 개체 용량 및 최대 용량을 설정할 수 있는 몇 가지 생성자가 있습니다. 기본 최대 용량이 약 20억자 정도이므로 용량을 다소 작은 값으로 설정하는 것이 좋습니다. 그렇다고 해서 작은 값을 설정하지 않는 것이 문제가 되는 것은 아닙니다. 개체 용량은 필요에 따라 최대 용량을 넘지 않는 한도에서 상향 조정될 수 있습니다. StringBuilder가 생성된 이후에는 최대 용량을 조절할 수 없습니다.

속성에는 네 가지가 있습니다. 읽고 쓸 수 있는 Capacity 속성, 읽기 전용인 MaxCapacity 속성, 문자열의 현재 길이를 나타내는 Length(더 길거나 짧게 설정할 수 있음) 속성 및 개별 문자를 읽고 쓸 수 있게 하는 인덱서인 Chars 속성 등입니다. 용량이 충분하지 않은 경우 EnsureCapacity 메서드를 사용하여 용량을 늘릴 수 있습니다.

Append 메서드를 사용하여 문자열이나 모든 형식(오버로드가 많이 있음)을 StringBuilder의 끝에 추가할 수 있습니다. 다른 형식을 전달하는 경우 해당 ToString 메서드가 호출되고 결과는 StringBuilder에 추가됩니다.

AppendFormat 메서드를 사용하여 StringBuilder에 추가하는 문자열에 서식을 지정할 수 있습니다. 서식은 String.FormatConsole.WriteLine과 같습니다.

Insert의 여러 오버로드를 사용하여 문자열(아마 매개 변수의 ToString 메서드에 대한 호출에서 계산된)을 StringBuilder의 어느 곳에나 삽입할 수 있습니다.

Remove를 사용하면 어떤 위치에서도 모든 수의 문자를 제거할 수 있습니다.

Replace를 사용하면 개별 문자나 방금 말한 대로 부분 문자열을 대체할 수 있습니다.

마지막으로 ToString의 오버로드는 StringBuilder(또는 StringBuilder의 지정된 부분 문자열)에서 String 개체를 새로 만들고 반환할 수 있습니다.

System.Text 인코더 및 디코더

.NET Framework 프로그램의 모든 문자열은 16비트 유니코드에 저장됩니다. 또한 모든 사람이 유니코드를 사용하는 것이 아니므로 때로는 일부 다른 문자 인코딩에서 유니코드로 또는 유니코드에서 일부 다른 문자 인코딩으로 변환해야 할 경우가 있습니다.

.NET Framework에서는 인코딩(유니코드 문자를 다른 인코딩의 바이트 블록으로 변환) 및 디코딩(일부 인코딩의 바이트 블록을 유니코드 문자로 변환)을 할 수 있는 여러 가지 클래스가 제공됩니다.

ASCIIEncoding, CodePageEncoding, UnicodeEncoding(big-endian에서 little-endian으로 변환하는 데 유용함), UTF7EncodingUTF8Encoding 등 각 지원된 인코딩에 대한 클래스가 있습니다.

이러한 각 클래스에는 단일 배열을 한 번에 인코딩하고 디코딩할 수 있는 인코딩(예: GetBytes) 및 디코딩(예: GetChars)에 대한 메서드가 있습니다. 또한, 각 클래스는 GetEncoderGetDecoder를 지원하며, 이것은 시프트 상태를 유지 관리할 수 있는 인코더 및 디코더를 반환하므로 스트림 및 블록과 함께 사용할 수 있습니다.

정규식

Visual Basic .NET에서는 Like 문을 통해 일치하는 제한된 정규식을 지원합니다. 또한 .NET Framework에서는 System.Text.RegularExpressions 네임스페이스에서 처리 중인 아주 복잡한 정규식을 지원합니다. 여기서 중요한 클래스는 컴파일된 정규식을 나타내고 이를 사용할 수 있는 메서드를 제공하는(문자열에서 정규식 찾기 및 대체, 문자열을 문자열 배열로 분할 등) System.Text.RegularExpressions.RegEx입니다. 정규식에 대한 설명서는 많지 않으므로 여기서는 자세히 다루지 않겠으며 아마 앞으로 나올 기사에서 다루게 될 것입니다.

시도해 봅시다.

.NET Framework Learning Team에는 누가 있습니까?

훌륭한 의사는 여러분이 .NET으로 시험해 보는 것 뿐만 아니라 다른 사람과 함께 작업하는 것도 바랍니다. 이렇게 하는 것이 더 재미있기도 하고, 배우는 점도 있을 것입니다.

다음을 시도해 보십시오.

문자열 및 문자열 배열을 가지고 시험을 해 봅니다.

StringBuilder로 문자열 조작을 합니다. String의 일부 고급 기능을 사용하여 문자열(아마도 명령줄)을 구문 분석합니다.

정말 재미있는 것을 원한다면 다른 문자 집합 및 코드 페이지를 인코딩하고 디코딩해 보십시오. 정말 새로운 것을 원한다면 정규식 클래스로 작업해 보십시오.

본 기사의 주제와 앞으로 다루게 될 주제

이번에는 문자열에 대해 설명했습니다. 다음에는 배열에 대해 이야기하겠습니다.



최종 수정일: 2002년 8월 1일
Top of Page Top of Page


Microsoft