System.String 클래스
이 문서에서는 이 API에 대한 참조 설명서에 대한 추가 설명서를 제공합니다.
문자열은 텍스트를 나타내는 데 사용되는 문자의 순차적 컬렉션입니다. String 개체는 문자열을 나타내는 개체의 System.Char 순차적 컬렉션이며, System.Char 개체는 UTF-16 코드 단위에 해당합니다. 개체의 String 값은 개체의 순차 컬렉션 내용 System.Char 이며 해당 값은 변경할 수 없습니다(즉, 읽기 전용). 문자열의 불변성에 대한 자세한 내용은 불변성 및 StringBuilder 클래스 섹션을 참조하세요. 메모리에 있는 개체의 String 최대 크기는 2GB 또는 약 10억 자입니다.
유니코드, UTF-16, 코드 단위, 코드 포인트 및 Char Rune 형식에 대한 자세한 내용은 .NET의 문자 인코딩 소개를 참조하세요.
String 개체 인스턴스화
다음과 같은 방법으로 개체를 String 인스턴스화할 수 있습니다.
변수에 문자열 리터럴을 String 할당합니다. 문자열을 만드는 데 가장 일반적으로 사용되는 메서드입니다. 다음 예제에서는 할당을 사용하여 여러 문자열을 만듭니다. C# 및 F#에서는 백슬래시(\)가 이스케이프 문자이기 때문에 문자열의 리터럴 백슬래시를 이스케이프하거나 전체 문자열을 @-quoted해야 합니다.
string string1 = "This is a string created by assignment."; Console.WriteLine(string1); string string2a = "The path is C:\\PublicDocuments\\Report1.doc"; Console.WriteLine(string2a); string string2b = @"The path is C:\PublicDocuments\Report1.doc"; Console.WriteLine(string2b); // The example displays the following output: // This is a string created by assignment. // The path is C:\PublicDocuments\Report1.doc // The path is C:\PublicDocuments\Report1.doc
let string1 = "This is a string created by assignment." printfn "%s" string1 let string2a = "The path is C:\\PublicDocuments\\Report1.doc" printfn "%s" string2a let string2b = @"The path is C:\PublicDocuments\Report1.doc" printfn "%s" string2b // The example displays the following output: // This is a string created by assignment. // The path is C:\PublicDocuments\Report1.doc // The path is C:\PublicDocuments\Report1.doc
Dim string1 As String = "This is a string created by assignment." Console.WriteLine(string1) Dim string2 As String = "The path is C:\PublicDocuments\Report1.doc" Console.WriteLine(string2) ' The example displays the following output: ' This is a string created by assignment. ' The path is C:\PublicDocuments\Report1.doc
클래스 생성자를 호출합니다 String . 다음 예제에서는 여러 클래스 생성자를 호출하여 문자열을 인스턴스화합니다. 일부 생성자에는 문자 배열에 대한 포인터 또는 서명된 바이트 배열이 매개 변수로 포함됩니다. Visual Basic은 이러한 생성자에 대한 호출을 지원하지 않습니다. 생성자에 대한 String 자세한 내용은 생성자 요약을 String 참조하세요.
char[] chars = { 'w', 'o', 'r', 'd' }; sbyte[] bytes = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x00 }; // Create a string from a character array. string string1 = new string(chars); Console.WriteLine(string1); // Create a string that consists of a character repeated 20 times. string string2 = new string('c', 20); Console.WriteLine(string2); string stringFromBytes = null; string stringFromChars = null; unsafe { fixed (sbyte* pbytes = bytes) { // Create a string from a pointer to a signed byte array. stringFromBytes = new string(pbytes); } fixed (char* pchars = chars) { // Create a string from a pointer to a character array. stringFromChars = new string(pchars); } } Console.WriteLine(stringFromBytes); Console.WriteLine(stringFromChars); // The example displays the following output: // word // cccccccccccccccccccc // ABCDE // word
let chars = [| 'w'; 'o'; 'r'; 'd' |] let bytes = [| 0x41y; 0x42y; 0x43y; 0x44y; 0x45y; 0x00y |] // Create a string from a character array. let string1 = String chars printfn "%s" string1 // Create a string that consists of a character repeated 20 times. let string2 = String('c', 20) printfn "%s" string2 let stringFromBytes = // Create a string from a pointer to a signed byte array. use pbytes = fixed bytes String pbytes let stringFromChars = // Create a string from a pointer to a character array. use pchars = fixed chars String pchars printfn $"{stringFromBytes}" printfn $"{stringFromChars}" // The example displays the following output: // word // cccccccccccccccccccc // ABCDE // word
Dim chars() As Char = {"w"c, "o"c, "r"c, "d"c} ' Create a string from a character array. Dim string1 As New String(chars) Console.WriteLine(string1) ' Create a string that consists of a character repeated 20 times. Dim string2 As New String("c"c, 20) Console.WriteLine(string2) ' The example displays the following output: ' word ' cccccccccccccccccccc
문자열 연결 연산자(C# 및 F#의 경우+ 및 Visual Basic의 경우 +)를 사용하여 인스턴스와 문자열 리터럴의 String 조합에서 단일 문자열을 만듭니다. 다음 예제에서는 문자열 연결 연산자의 사용을 보여 줍니다.
string string1 = "Today is " + DateTime.Now.ToString("D") + "."; Console.WriteLine(string1); string string2 = "This is one sentence. " + "This is a second. "; string2 += "This is a third sentence."; Console.WriteLine(string2); // The example displays output like the following: // Today is Tuesday, July 06, 2011. // This is one sentence. This is a second. This is a third sentence.
let string1 = "Today is " + DateTime.Now.ToString("D") + "." printfn $"{string1}" let string2 = "This is one sentence. " + "This is a second. " let string2 = string2 + "This is a third sentence." printfn $"{string2}" // The example displays output like the following: // Today is Tuesday, July 06, 2011. // This is one sentence. This is a second. This is a third sentence.
Dim string1 As String = "Today is " + Date.Now.ToString("D") + "." Console.WriteLine(string1) Dim string2 As String = "This is one sentence. " + "This is a second. " string2 += "This is a third sentence." Console.WriteLine(string2) ' The example displays output like the following: ' Today is Tuesday, July 06, 2011. ' This is one sentence. This is a second. This is a third sentence.
속성을 검색하거나 문자열을 반환하는 메서드를 호출합니다. 다음 예제에서는 클래스의 메서드를 String 사용하여 더 큰 문자열에서 부분 문자열을 추출합니다.
string sentence = "This sentence has five words."; // Extract the second word. int startPosition = sentence.IndexOf(" ") + 1; string word2 = sentence.Substring(startPosition, sentence.IndexOf(" ", startPosition) - startPosition); Console.WriteLine("Second word: " + word2); // The example displays the following output: // Second word: sentence
let sentence = "This sentence has five words." // Extract the second word. let startPosition = sentence.IndexOf " " + 1 let word2 = sentence.Substring(startPosition, sentence.IndexOf(" ", startPosition) - startPosition) printfn $"Second word: {word2}" // The example displays the following output: // Second word: sentence
Dim sentence As String = "This sentence has five words." ' Extract the second word. Dim startPosition As Integer = sentence.IndexOf(" ") + 1 Dim word2 As String = sentence.Substring(startPosition, sentence.IndexOf(" ", startPosition) - startPosition) Console.WriteLine("Second word: " + word2) ' The example displays the following output: ' Second word: sentence
형식 지정 메서드를 호출하여 값 또는 개체를 문자열 표현으로 변환합니다. 다음 예제에서는 복합 서식 지정 기능을 사용하여 두 개체의 문자열 표현을 문자열에 포함합니다.
DateTime dateAndTime = new DateTime(2011, 7, 6, 7, 32, 0); double temperature = 68.3; string result = String.Format("At {0:t} on {0:D}, the temperature was {1:F1} degrees Fahrenheit.", dateAndTime, temperature); Console.WriteLine(result); // The example displays the following output: // At 7:32 AM on Wednesday, July 06, 2011, the temperature was 68.3 degrees Fahrenheit.
let dateAndTime = DateTime(2011, 7, 6, 7, 32, 0) let temperature = 68.3 String.Format("At {0:t} on {0:D}, the temperature was {1:F1} degrees Fahrenheit.", dateAndTime, temperature) |> printfn "%s" // The example displays the following output: // At 7:32 AM on Wednesday, July 06, 2011, the temperature was 68.3 degrees Fahrenheit.
Dim dateAndTime As DateTime = #07/06/2011 7:32:00AM# Dim temperature As Double = 68.3 Dim result As String = String.Format("At {0:t} on {0:D}, the temperature was {1:F1} degrees Fahrenheit.", dateAndTime, temperature) Console.WriteLine(result) ' The example displays the following output: ' At 7:32 AM on Wednesday, July 06, 2011, the temperature was 68.3 degrees Fahrenheit.
Char 개체 및 유니코드 문자
문자열의 각 문자는 유니코드 코드 포인트 또는 유니코드 문자의 서수(숫자) 값이라고도 하는 유니코드 스칼라 값으로 정의됩니다. 각 코드 포인트는 UTF-16 인코딩을 사용하여 인코딩되고 인코딩의 각 요소의 숫자 값은 개체로 Char 표시됩니다.
참고 항목
인스턴스는 String UTF-16 코드 단위의 순차 컬렉션으로 구성되므로 올바른 형식의 유니코드 문자열이 아닌 개체를 만들 String 수 있습니다. 예를 들어 해당 상위 서로게이트 없이 서로게이트가 낮은 문자열을 만들 수 있습니다. 네임스페이스에서 개체 System.Text 를 인코딩 및 디코딩하는 메서드와 같은 일부 메서드는 문자열이 올바른 형식인지 확인하는 검사를 수행할 수 있지만 클래스 String 멤버는 문자열의 형식이 올바른지 확인할 수 없습니다.
단일 Char 개체는 일반적으로 단일 코드 포인트를 나타냅니다. 즉, 숫자 값 Char 은 코드 포인트와 같습니다. 예를 들어 문자 "a"의 코드 포인트는 U+0061입니다. 그러나 코드 포인트에는 둘 이상의 인코딩된 요소(둘 Char 이상의 개체)가 필요할 수 있습니다. 유니코드 표준은 여러 Char 개체에 해당하는 두 가지 유형의 문자를 정의합니다. 즉, 그래프와 유니코드 보조 평면의 문자에 해당하는 유니코드 보조 코드 포인트입니다.
그래프는 기본 문자 뒤에 하나 이상의 결합 문자로 표시됩니다. 예를 들어 ä 문자는 코드 포인트가 U+0061인 개체와 Char 코드 포인트가 U+0308인 개체로 표시됩니다Char. 이 문자는 코드 포인트가 U+00E4인 단일 Char 개체로 정의할 수도 있습니다. 다음 예제와 같이 같음의 문화권 구분 비교는 일반 서수 비교는 그렇지 않지만 이러한 두 표현이 같음을 나타냅니다. 그러나 두 문자열이 정규화된 경우 서수 비교는 해당 문자열이 같음도 나타냅니다. (문자열 정규화에 대한 자세한 내용은 다음을 참조하세요 .정규화 섹션.)
using System; using System.Globalization; using System.IO; public class Example5 { public static void Main() { StreamWriter sw = new StreamWriter(@".\graphemes.txt"); string grapheme = "\u0061\u0308"; sw.WriteLine(grapheme); string singleChar = "\u00e4"; sw.WriteLine(singleChar); sw.WriteLine("{0} = {1} (Culture-sensitive): {2}", grapheme, singleChar, String.Equals(grapheme, singleChar, StringComparison.CurrentCulture)); sw.WriteLine("{0} = {1} (Ordinal): {2}", grapheme, singleChar, String.Equals(grapheme, singleChar, StringComparison.Ordinal)); sw.WriteLine("{0} = {1} (Normalized Ordinal): {2}", grapheme, singleChar, String.Equals(grapheme.Normalize(), singleChar.Normalize(), StringComparison.Ordinal)); sw.Close(); } } // The example produces the following output: // ä // ä // ä = ä (Culture-sensitive): True // ä = ä (Ordinal): False // ä = ä (Normalized Ordinal): True
open System open System.IO do use sw = new StreamWriter(@".\graphemes.txt") let grapheme = "\u0061\u0308" sw.WriteLine grapheme let singleChar = "\u00e4" sw.WriteLine singleChar sw.WriteLine("{0} = {1} (Culture-sensitive): {2}", grapheme, singleChar, String.Equals(grapheme, singleChar, StringComparison.CurrentCulture)) sw.WriteLine("{0} = {1} (Ordinal): {2}", grapheme, singleChar, String.Equals(grapheme, singleChar, StringComparison.Ordinal)) sw.WriteLine("{0} = {1} (Normalized Ordinal): {2}", grapheme, singleChar, String.Equals(grapheme.Normalize(), singleChar.Normalize(), StringComparison.Ordinal)) // The example produces the following output: // ä // ä // ä = ä (Culture-sensitive): True // ä = ä (Ordinal): False // ä = ä (Normalized Ordinal): True
Imports System.Globalization Imports System.IO Module Example9 Public Sub Main() Dim sw As New StreamWriter(".\graphemes.txt") Dim grapheme As String = ChrW(&H61) + ChrW(&H308) sw.WriteLine(grapheme) Dim singleChar As String = ChrW(&HE4) sw.WriteLine(singleChar) sw.WriteLine("{0} = {1} (Culture-sensitive): {2}", grapheme, singleChar, String.Equals(grapheme, singleChar, StringComparison.CurrentCulture)) sw.WriteLine("{0} = {1} (Ordinal): {2}", grapheme, singleChar, String.Equals(grapheme, singleChar, StringComparison.Ordinal)) sw.WriteLine("{0} = {1} (Normalized Ordinal): {2}", grapheme, singleChar, String.Equals(grapheme.Normalize(), singleChar.Normalize(), StringComparison.Ordinal)) sw.Close() End Sub End Module ' The example produces the following output: ' ä ' ä ' ä = ä (Culture-sensitive): True ' ä = ä (Ordinal): False ' ä = ä (Normalized Ordinal): True
유니코드 보조 코드 지점(서로게이트 쌍)은 코드 포인트가 높은 서로게이트인 개체와 Char 코드 포인트가 낮은 서로게이트인 개체로 표시됩니다Char. 상위 서로게이트의 코드 단위는 U+D800에서 U+DBFF까지 다양합니다. 낮은 서로게이트의 코드 단위는 U+DC00에서 U+DFFF까지 다양합니다. 서로게이트 쌍은 16개의 유니코드 보조 평면의 문자를 나타내는 데 사용됩니다. 다음 예제에서는 서로게이트 문자를 만들고 메서드에 Char.IsSurrogatePair(Char, Char) 전달하여 서로게이트 쌍인지 여부를 확인합니다.
string surrogate = "\uD800\uDC03"; for (int ctr = 0; ctr < surrogate.Length; ctr++) Console.Write($"U+{(ushort)surrogate[ctr]:X2} "); Console.WriteLine(); Console.WriteLine(" Is Surrogate Pair: {0}", Char.IsSurrogatePair(surrogate[0], surrogate[1])); // The example displays the following output: // U+D800 U+DC03 // Is Surrogate Pair: True
open System let surrogate = "\uD800\uDC03" for i = 0 to surrogate.Length - 1 do printf $"U+{uint16 surrogate[i]:X2} " printfn $"\n Is Surrogate Pair: {Char.IsSurrogatePair(surrogate[0], surrogate[1])}" // The example displays the following output: // U+D800 U+DC03 // Is Surrogate Pair: True
Module Example20 Public Sub Main() Dim surrogate As String = ChrW(&HD800) + ChrW(&HDC03) For ctr As Integer = 0 To surrogate.Length - 1 Console.Write("U+{0:X2} ", Convert.ToUInt16(surrogate(ctr))) Next Console.WriteLine() Console.WriteLine(" Is Surrogate Pair: {0}", Char.IsSurrogatePair(surrogate(0), surrogate(1))) End Sub End Module ' The example displays the following output: ' U+D800 U+DC03 ' Is Surrogate Pair: True
유니코드 표준
문자열의 문자는 값에 해당하는 UTF-16으로 인코딩된 코드 단위로 Char 표시됩니다.
문자열의 각 문자에는 열거형으로 .NET에 표시되는 연결된 유니코드 문자 범주가 UnicodeCategory 있습니다. 문자 또는 서로게이트 쌍의 범주는 메서드를 호출 CharUnicodeInfo.GetUnicodeCategory 하여 확인할 수 있습니다.
.NET에서는 문자 및 해당 범주의 고유한 테이블을 유지 관리합니다. 그러면 다른 플랫폼에서 실행되는 특정 버전의 .NET 구현이 동일한 문자 범주 정보를 반환하게 됩니다. 모든 .NET 버전 및 모든 OS 플랫폼에서 문자 범주 정보는 유니코드 문자 데이터베이스에서 제공됩니다.
다음 표에서는 해당 문자 범주의 기반이 되는 .NET 버전 및 유니코드 표준 버전을 나열합니다.
.NET 버전 | 유니코드 표준 버전 |
---|---|
.NET Framework 1.1 | 유니코드 표준, 버전 4.0.0 |
.NET Framework 2.0 | 유니코드 표준, 버전 5.0.0 |
.NET Framework 3.5 | 유니코드 표준, 버전 5.0.0 |
.NET Framework 4 | 유니코드 표준, 버전 5.0.0 |
.NET Framework 4.5 | 유니코드 표준, 버전 6.3.0 |
.NET Framework 4.5.1 | 유니코드 표준, 버전 6.3.0 |
.NET Framework 4.5.2 | 유니코드 표준, 버전 6.3.0 |
.NET Framework 4.6 | 유니코드 표준, 버전 6.3.0 |
.NET Framework 4.6.1 | 유니코드 표준, 버전 6.3.0 |
.NET Framework 4.6.2 이전 버전 | 유니코드 표준, 버전 8.0.0 |
.NET Core 2.1 | 유니코드 표준, 버전 8.0.0 |
.NET Core 3.1 | 유니코드 표준 버전 11.0.0 |
.NET 5 | 유니코드 표준 버전 13.0.0 |
또한 .NET은 유니코드 표준에 따라 문자열 비교 및 정렬을 지원합니다. Windows 8 이상 버전의 Windows 운영 체제에서 실행되는 .NET Framework 4.5부터 런타임은 문자열 비교 및 정렬 작업을 운영 체제에 위임합니다. .NET Core 및 .NET 5 이상에서는 유니코드 라이브러리용 International Components(Windows 10 2019년 5월 업데이트 이전 Windows 버전 제외)에서 문자열 비교 및 정렬 정보를 제공합니다. 다음 표에서는 .NET 버전과 문자 비교 및 정렬의 기반이 되는 유니코드 표준 버전을 나열합니다.
.NET 버전 | 유니코드 표준 버전 |
---|---|
Windows 7의 .NET Framework 4.5 이상 | 유니코드 표준, 버전 5.0.0 |
Windows 8 이상 Windows 운영 체제의 .NET Framework 4.5 이상 | 유니코드 표준, 버전 6.3.0 |
.NET Core 및 .NET 5 이상 | 기본 운영 체제에서 지원되는 유니코드 표준의 버전에 따라 달라집니다. |
포함된 null 문자
.NET에서 개체는 String 문자열 길이의 일부로 계산되는 포함된 null 문자를 포함할 수 있습니다. 그러나 C 및 C++와 같은 일부 언어에서는 null 문자가 문자열의 끝을 나타냅니다. 문자열의 일부로 간주되지 않으며 문자열 길이의 일부로 계산되지 않습니다. 즉, C 및 C++ 프로그래머 또는 C 또는 C++로 작성된 라이브러리가 문자열에 대해 만들 수 있는 다음과 같은 일반적인 가정은 개체에 적용할 String 때 반드시 유효하지는 않습니다.
또는
wcslen
함수에서 반환된 값이strlen
반드시 같은 String.Length것은 아닙니다.또는
wcscpy_s
함수에서strcpy_s
만든 문자열이 복사되는 문자열과 반드시 동일하지는 않습니다.
개체를 인스턴스화하는 String 네이티브 C 및 C++ 코드와 플랫폼 호출을 통해 전달된 String 개체가 포함된 null 문자가 문자열의 끝을 표시한다고 가정하지 않도록 해야 합니다.
문자열에 포함된 null 문자는 문자열을 정렬(또는 비교)하고 문자열을 검색할 때도 다르게 처리됩니다. 고정 문화권을 사용한 비교를 포함하여 두 문자열 간에 문화권 구분 비교를 수행하는 경우 Null 문자는 무시됩니다. 서수 또는 대/소문자를 구분하지 않는 서수 비교에 대해서만 고려됩니다. 반면에 포함된 null 문자는 메서드(예 Contains: , StartsWith및 IndexOf)를 사용하여 문자열을 검색할 때 항상 고려됩니다.
문자열 및 인덱스
인덱스는 .에서 유니코드 문자가 아닌 개체의 Char 위치입니다 String. 인덱스는 문자열의 첫 번째 위치(인덱스 위치 0)에서 시작하는 0부터 시작하는 음수입니다. 문자열 인스턴스에서 문자 또는 부분 문자열의 인덱스와 같은 IndexOf LastIndexOf다양한 검색 메서드를 반환합니다.
이 Chars[] 속성을 사용하면 문자열의 인덱스 위치로 개별 Char 개체에 액세스할 수 있습니다. Chars[] 속성은 기본 속성(Visual Basic) 또는 인덱서(C# 및 F#)이므로 다음과 같은 코드를 사용하여 문자열의 개별 Char 개체에 액세스할 수 있습니다. 이 코드는 문자열에서 공백 또는 문장 부호 문자를 검색하여 문자열에 포함된 단어 수를 결정합니다.
string s1 = "This string consists of a single short sentence.";
int nWords = 0;
s1 = s1.Trim();
for (int ctr = 0; ctr < s1.Length; ctr++) {
if (Char.IsPunctuation(s1[ctr]) | Char.IsWhiteSpace(s1[ctr]))
nWords++;
}
Console.WriteLine("The sentence\n {0}\nhas {1} words.",
s1, nWords);
// The example displays the following output:
// The sentence
// This string consists of a single short sentence.
// has 8 words.
let s1 = "This string consists of a single short sentence."
let mutable nWords = 0
for i = 0 to s1.Length - 1 do
if Char.IsPunctuation s1[i] || Char.IsWhiteSpace s1[i] then
nWords <- nWords + 1
printfn $"The sentence\n {s1}\nhas {nWords} words."
// The example displays the following output:
// The sentence
// This string consists of a single short sentence.
// has 8 words.
Module Example12
Public Sub Main()
Dim s1 As String = "This string consists of a single short sentence."
Dim nWords As Integer = 0
s1 = s1.Trim()
For ctr As Integer = 0 To s1.Length - 1
If Char.IsPunctuation(s1(ctr)) Or Char.IsWhiteSpace(s1(ctr)) Then
nWords += 1
End If
Next
Console.WriteLine("The sentence{2} {0}{2}has {1} words.",
s1, nWords, vbCrLf)
End Sub
End Module
' The example displays the following output:
' The sentence
' This string consists of a single short sentence.
' has 8 words.
클래스는 String 인터페이스를 IEnumerable 구현하기 때문에 다음 예제와 같이 구문을 사용하여 foreach
문자열의 개체를 반복할 Char 수도 있습니다.
string s1 = "This string consists of a single short sentence.";
int nWords = 0;
s1 = s1.Trim();
foreach (var ch in s1) {
if (Char.IsPunctuation(ch) | Char.IsWhiteSpace(ch))
nWords++;
}
Console.WriteLine("The sentence\n {0}\nhas {1} words.",
s1, nWords);
// The example displays the following output:
// The sentence
// This string consists of a single short sentence.
// has 8 words.
let s1 = "This string consists of a single short sentence."
let mutable nWords = 0
for ch in s1 do
if Char.IsPunctuation ch || Char.IsWhiteSpace ch then
nWords <- nWords + 1
printfn $"The sentence\n {s1}\nhas {nWords} words."
// The example displays the following output:
// The sentence
// This string consists of a single short sentence.
// has 8 words.
Module Example13
Public Sub Main()
Dim s1 As String = "This string consists of a single short sentence."
Dim nWords As Integer = 0
s1 = s1.Trim()
For Each ch In s1
If Char.IsPunctuation(ch) Or Char.IsWhiteSpace(ch) Then
nWords += 1
End If
Next
Console.WriteLine("The sentence{2} {0}{2}has {1} words.",
s1, nWords, vbCrLf)
End Sub
End Module
' The example displays the following output:
' The sentence
' This string consists of a single short sentence.
' has 8 words.
유니코드 문자가 둘 Char 이상의 개체로 인코딩될 수 있으므로 연속 인덱스 값은 연속 유니코드 문자에 해당하지 않을 수 있습니다. 특히 문자열에는 기본 문자 다음에 하나 이상의 결합 문자 또는 서로게이트 쌍에 의해 형성되는 텍스트의 여러 문자 단위가 포함될 수 있습니다. 개체 대신 Char 유니코드 문자를 사용하려면 및 TextElementEnumerator 클래스 또는 String.EnumerateRunes 메서드와 구조체를 Rune 사용합니다System.Globalization.StringInfo. 다음 예제에서는 개체와 함께 작동하는 코드와 유니코드 문자로 Char 작동하는 코드의 차이점을 보여 줍니다. 문장의 각 단어에 있는 문자 또는 텍스트 요소의 수를 비교합니다. 문자열에는 기본 문자의 두 시퀀스 뒤에 결합 문자가 포함됩니다.
// First sentence of The Mystery of the Yellow Room, by Leroux.
string opening = "Ce n'est pas sans une certaine émotion que "+
"je commence à raconter ici les aventures " +
"extraordinaires de Joseph Rouletabille.";
// Character counters.
int nChars = 0;
// Objects to store word count.
List<int> chars = new List<int>();
List<int> elements = new List<int>();
foreach (var ch in opening) {
// Skip the ' character.
if (ch == '\u0027') continue;
if (Char.IsWhiteSpace(ch) | (Char.IsPunctuation(ch))) {
chars.Add(nChars);
nChars = 0;
}
else {
nChars++;
}
}
System.Globalization.TextElementEnumerator te =
System.Globalization.StringInfo.GetTextElementEnumerator(opening);
while (te.MoveNext()) {
string s = te.GetTextElement();
// Skip the ' character.
if (s == "\u0027") continue;
if ( String.IsNullOrEmpty(s.Trim()) | (s.Length == 1 && Char.IsPunctuation(Convert.ToChar(s)))) {
elements.Add(nChars);
nChars = 0;
}
else {
nChars++;
}
}
// Display character counts.
Console.WriteLine("{0,6} {1,20} {2,20}",
"Word #", "Char Objects", "Characters");
for (int ctr = 0; ctr < chars.Count; ctr++)
Console.WriteLine("{0,6} {1,20} {2,20}",
ctr, chars[ctr], elements[ctr]);
// The example displays the following output:
// Word # Char Objects Characters
// 0 2 2
// 1 4 4
// 2 3 3
// 3 4 4
// 4 3 3
// 5 8 8
// 6 8 7
// 7 3 3
// 8 2 2
// 9 8 8
// 10 2 1
// 11 8 8
// 12 3 3
// 13 3 3
// 14 9 9
// 15 15 15
// 16 2 2
// 17 6 6
// 18 12 12
open System
open System.Globalization
// First sentence of The Mystery of the Yellow Room, by Leroux.
let opening = "Ce n'est pas sans une certaine émotion que je commence à raconter ici les aventures extraordinaires de Joseph Rouletabille."
// Character counters.
let mutable nChars = 0
// Objects to store word count.
let chars = ResizeArray<int>()
let elements = ResizeArray<int>()
for ch in opening do
// Skip the ' character.
if ch <> '\u0027' then
if Char.IsWhiteSpace ch || Char.IsPunctuation ch then
chars.Add nChars
nChars <- 0
else
nChars <- nChars + 1
let te = StringInfo.GetTextElementEnumerator opening
while te.MoveNext() do
let s = te.GetTextElement()
// Skip the ' character.
if s <> "\u0027" then
if String.IsNullOrEmpty(s.Trim()) || (s.Length = 1 && Char.IsPunctuation(Convert.ToChar s)) then
elements.Add nChars
nChars <- 0
else
nChars <- nChars + 1
// Display character counts.
printfn "%6s %20s %20s" "Word #" "Char Objects " "Characters"
for i = 0 to chars.Count - 1 do
printfn "%6d %20d %20d" i chars[i] elements[i]
// The example displays the following output:
// Word # Char Objects Characters
// 0 2 2
// 1 4 4
// 2 3 3
// 3 4 4
// 4 3 3
// 5 8 8
// 6 8 7
// 7 3 3
// 8 2 2
// 9 8 8
// 10 2 1
// 11 8 8
// 12 3 3
// 13 3 3
// 14 9 9
// 15 15 15
// 16 2 2
// 17 6 6
// 18 12 12
Imports System.Collections.Generic
Imports System.Globalization
Module Example14
Public Sub Main()
' First sentence of The Mystery of the Yellow Room, by Leroux.
Dim opening As String = "Ce n'est pas sans une certaine émotion que " +
"je commence à raconter ici les aventures " +
"extraordinaires de Joseph Rouletabille."
' Character counters.
Dim nChars As Integer = 0
' Objects to store word count.
Dim chars As New List(Of Integer)()
Dim elements As New List(Of Integer)()
For Each ch In opening
' Skip the ' character.
If ch = ChrW(&H27) Then Continue For
If Char.IsWhiteSpace(ch) Or Char.IsPunctuation(ch) Then
chars.Add(nChars)
nChars = 0
Else
nChars += 1
End If
Next
Dim te As TextElementEnumerator = StringInfo.GetTextElementEnumerator(opening)
Do While te.MoveNext()
Dim s As String = te.GetTextElement()
' Skip the ' character.
If s = ChrW(&H27) Then Continue Do
If String.IsNullOrEmpty(s.Trim()) Or (s.Length = 1 AndAlso Char.IsPunctuation(Convert.ToChar(s))) Then
elements.Add(nChars)
nChars = 0
Else
nChars += 1
End If
Loop
' Display character counts.
Console.WriteLine("{0,6} {1,20} {2,20}",
"Word #", "Char Objects", "Characters")
For ctr As Integer = 0 To chars.Count - 1
Console.WriteLine("{0,6} {1,20} {2,20}",
ctr, chars(ctr), elements(ctr))
Next
End Sub
End Module
' The example displays the following output:
' Word # Char Objects Characters
' 0 2 2
' 1 4 4
' 2 3 3
' 3 4 4
' 4 3 3
' 5 8 8
' 6 8 7
' 7 3 3
' 8 2 2
' 9 8 8
' 10 2 1
' 11 8 8
' 12 3 3
' 13 3 3
' 14 9 9
' 15 15 15
' 16 2 2
' 17 6 6
' 18 12 12
이 예제에서는 메서드와 클래스를 사용하여 문자열의 StringInfo.GetTextElementEnumerator TextElementEnumerator 모든 텍스트 요소를 열거하여 텍스트 요소에서 작동합니다. 메서드를 호출하여 각 텍스트 요소의 시작 인덱스가 포함된 배열을 검색할 StringInfo.ParseCombiningCharacters 수도 있습니다.
개별 Char 값이 아닌 텍스트 단위를 사용하는 방법에 대한 자세한 내용은 .NET의 문자 인코딩 소개를 참조하세요.
Null 문자열 및 빈 문자열
선언되었지만 값이 할당되지 않은 문자열은 다음과 입니다 null
. 해당 문자열에서 메서드를 호출하려고 시도하면 .NullReferenceException null 문자열은 값이 "" 또는 String.Empty"인 문자열인 빈 문자열과 다릅니다. 경우에 따라 null 문자열 또는 빈 문자열을 메서드 호출의 인수로 전달하면 예외가 throw됩니다. 예를 들어 메서드ArgumentNullException에 null 문자열을 전달하면 Int32.Parse 빈 문자열이 throw되고 빈 문자열을 전달하면 .FormatException 다른 경우에는 메서드 인수가 null 문자열이거나 빈 문자열일 수 있습니다. 예를 들어 클래스에 대한 구현을 IFormattable 제공하는 경우 null 문자열과 빈 문자열을 모두 일반("G") 형식 지정자와 동일시하려고 합니다.
이 String 클래스에는 문자열이 비어 있는지 여부를 테스트할 수 있는 다음과 같은 두 가지 편리한 메서드가 포함되어 있습니다 null
.
IsNullOrEmpty문자열
null
이 같거나 같은지 여부를 나타내는 String.Empty입니다. 이 메서드는 다음과 같은 코드를 사용할 필요가 없습니다.if (str == null || str.Equals(String.Empty))
if str = null || str.Equals String.Empty then
If str Is Nothing OrElse str.Equals(String.Empty) Then
IsNullOrWhiteSpace문자열이 공백 문자로만 구성되어 있는지 여부를 나타내는 입니다
null
String.Empty. 이 메서드는 다음과 같은 코드를 사용할 필요가 없습니다.if (str == null || str.Equals(String.Empty) || str.Trim().Equals(String.Empty))
if str = null || str.Equals String.Empty || str.Trim().Equals String.Empty then
If str Is Nothing OrElse str.Equals(String.Empty) OrElse str.Trim().Equals(String.Empty) Then
다음 예제에서는 사용자 지정 Temperature
클래스의 구현에서 IFormattable.ToString 메서드를 사용합니다IsNullOrEmpty. 이 메서드는 "G", "C", "F" 및 "K" 형식 문자열을 지원합니다. 빈 서식 문자열 또는 값이 null
메서드에 전달되는 서식 문자열인 경우 해당 값은 "G" 형식 문자열로 변경됩니다.
public string ToString(string format, IFormatProvider provider)
{
if (String.IsNullOrEmpty(format)) format = "G";
if (provider == null) provider = CultureInfo.CurrentCulture;
switch (format.ToUpperInvariant())
{
// Return degrees in Celsius.
case "G":
case "C":
return temp.ToString("F2", provider) + "°C";
// Return degrees in Fahrenheit.
case "F":
return (temp * 9 / 5 + 32).ToString("F2", provider) + "°F";
// Return degrees in Kelvin.
case "K":
return (temp + 273.15).ToString();
default:
throw new FormatException(
String.Format("The {0} format string is not supported.",
format));
}
}
member _.ToString(format: string, provider: IFormatProvider) =
let format =
if String.IsNullOrEmpty format then "G" else format
let provider: IFormatProvider =
if provider = null then CultureInfo.CurrentCulture else provider
match format.ToUpperInvariant() with
// Return degrees in Celsius.
| "G"
| "C" ->
temp.ToString("F2", provider) + "°C"
// Return degrees in Fahrenheit.
| "F" ->
(temp * 9. / 5. + 32.).ToString("F2", provider) + "°F"
// Return degrees in Kelvin.
| "K" ->
(temp + 273.15).ToString()
| _ ->
raise (FormatException(String.Format("The {0} format string is not supported.",format)))
Public Overloads Function ToString(fmt As String, provider As IFormatProvider) As String _
Implements IFormattable.ToString
If String.IsNullOrEmpty(fmt) Then fmt = "G"
If provider Is Nothing Then provider = CultureInfo.CurrentCulture
Select Case fmt.ToUpperInvariant()
' Return degrees in Celsius.
Case "G", "C"
Return temp.ToString("F2", provider) + "°C"
' Return degrees in Fahrenheit.
Case "F"
Return (temp * 9 / 5 + 32).ToString("F2", provider) + "°F"
' Return degrees in Kelvin.
Case "K"
Return (temp + 273.15).ToString()
Case Else
Throw New FormatException(
String.Format("The {0} format string is not supported.",
fmt))
End Select
End Function
불변성 및 StringBuilder 클래스
String 개체를 만든 후에는 값을 수정할 수 없으므로 변경할 수 없음(읽기 전용)이라고 합니다. 개체를 수정하는 것처럼 보이는 메서드는 String 실제로 수정 내용이 포함된 새 String 개체를 반환합니다.
문자열은 변경할 수 없으므로 단일 문자열로 보이는 항목에 반복 추가 또는 삭제를 수행하는 문자열 조작 루틴은 상당한 성능 저하를 초래합니다. 예를 들어 다음 코드는 난수 생성기를 사용하여 0x052F 범위 0x0001 1000자의 문자열을 만듭니다. 코드는 문자열 연결을 사용하여 이름이 지정된 str
기존 문자열에 새 문자를 추가하는 것처럼 보이지만 실제로 각 연결 작업에 대해 새 String 개체를 만듭니다.
using System;
using System.IO;
using System.Text;
public class Example6
{
public static void Main()
{
Random rnd = new Random();
string str = String.Empty;
StreamWriter sw = new StreamWriter(@".\StringFile.txt",
false, Encoding.Unicode);
for (int ctr = 0; ctr <= 1000; ctr++) {
str += (char)rnd.Next(1, 0x0530);
if (str.Length % 60 == 0)
str += Environment.NewLine;
}
sw.Write(str);
sw.Close();
}
}
open System
open System.IO
open System.Text
do
let rnd = Random()
let mutable str = String.Empty
use sw = new StreamWriter(@".\StringFile.txt", false, Encoding.Unicode)
for _ = 0 to 1000 do
str <- str + (rnd.Next(1, 0x0530) |> char |> string)
if str.Length % 60 = 0 then
str <- str + Environment.NewLine
sw.Write str
Imports System.IO
Imports System.Text
Module Example10
Public Sub Main()
Dim rnd As New Random()
Dim str As String = String.Empty
Dim sw As New StreamWriter(".\StringFile.txt",
False, Encoding.Unicode)
For ctr As Integer = 0 To 1000
str += ChrW(rnd.Next(1, &H530))
If str.Length Mod 60 = 0 Then str += vbCrLf
Next
sw.Write(str)
sw.Close()
End Sub
End Module
문자열 값을 여러 개 변경하는 작업에 클래스 대신 String 클래스를 사용할 StringBuilder 수 있습니다. 클래스 StringBuilder 의 String 인스턴스와 달리 개체는 변경할 수 있습니다. 문자열에서 부분 문자열을 연결, 추가 또는 삭제하면 단일 문자열에서 작업이 수행됩니다. 개체 값 수정을 마쳤으면 메서드 StringBuilder.ToString 를 StringBuilder 호출하여 문자열로 변환할 수 있습니다. 다음 예제에서는 개체로 0x052F 위해 0x0001 범위에서 1000개의 임의 문자를 연결하기 위해 이전 예제에서 StringBuilder 사용된 문자를 바꿉 String 니다.
using System;
using System.IO;
using System.Text;
public class Example10
{
public static void Main()
{
Random rnd = new Random();
StringBuilder sb = new StringBuilder();
StreamWriter sw = new StreamWriter(@".\StringFile.txt",
false, Encoding.Unicode);
for (int ctr = 0; ctr <= 1000; ctr++) {
sb.Append((char)rnd.Next(1, 0x0530));
if (sb.Length % 60 == 0)
sb.AppendLine();
}
sw.Write(sb.ToString());
sw.Close();
}
}
open System
open System.IO
open System.Text
do
let rnd = Random()
let sb = StringBuilder()
use sw = new StreamWriter(@".\StringFile.txt", false, Encoding.Unicode)
for _ = 0 to 1000 do
sb.Append(rnd.Next(1, 0x0530) |> char) |> ignore
if sb.Length % 60 = 0 then
sb.AppendLine() |> ignore
sw.Write(string sb)
Imports System.IO
Imports System.Text
Module Example11
Public Sub Main()
Dim rnd As New Random()
Dim sb As New StringBuilder()
Dim sw As New StreamWriter(".\StringFile.txt",
False, Encoding.Unicode)
For ctr As Integer = 0 To 1000
sb.Append(ChrW(rnd.Next(1, &H530)))
If sb.Length Mod 60 = 0 Then sb.AppendLine()
Next
sw.Write(sb.ToString())
sw.Close()
End Sub
End Module
서수 및 문화권 구분 작업
클래스의 멤버는 String 개체에 대해 서수 또는 문화권 구분(언어) 작업을 수행합니다 String . 서수 작업은 각 Char 개체의 숫자 값에 대해 작동합니다. 문화권 구분 작업은 개체의 String 값에 대해 작동하며 문화권별 대/소문자 구분, 정렬, 서식 지정 및 구문 분석 규칙을 고려합니다. 문화권 구분 작업은 명시적으로 선언된 문화권 또는 암시적 현재 문화권의 컨텍스트에서 실행됩니다. 두 종류의 연산은 동일한 문자열에서 수행될 때 매우 다른 결과를 생성할 수 있습니다.
또한 .NET은 지역과 독립적인 영어의 문화권 설정을 기반으로 하는 고정 문화권()CultureInfo.InvariantCulture을 사용하여 문화권을 구분하지 않는 언어 문자열 작업을 지원합니다. 다른 System.Globalization.CultureInfo 설정과 달리 고정 문화권의 설정은 단일 컴퓨터, 시스템 간 및 .NET 버전에서 일관성을 유지하도록 보장됩니다. 고정 문화권은 모든 문화권에서 문자열 비교 및 순서의 안정성을 보장하는 블랙 박스의 일종으로 볼 수 있습니다.
Important
애플리케이션 파일 이름과 같은 기호 식별자에 대 한 보안 결정을 내리는 또는 명명 된 파이프 하는 경우, XML 파일에 텍스트 기반 데이터와 같은 지속형된 데이터에 대 한 작업 대신 문화권 구분 비교는 서 수 비교를 사용 해야 합니다. 이는 문화권 구분 비교가 적용된 문화권에 따라 다른 결과를 얻을 수 있는 반면 서수 비교는 비교된 문자의 이진 값에만 의존하기 때문입니다.
Important
문자열 작업을 수행하는 대부분의 메서드에는 형식 StringComparison매개 변수가 있는 오버로드가 포함되며, 이를 통해 메서드가 서수 또는 문화권 구분 연산을 수행할지 여부를 지정할 수 있습니다. 일반적으로 메서드 호출의 의도를 명확하게 하려면 이 오버로드를 호출해야 합니다. 문자열에서 서수 및 문화권 구분 작업을 사용하는 모범 사례 및 지침은 문자열 사용에 대한 모범 사례를 참조 하세요.
대/소문자 구분, 구문 분석 및 서식 지정, 비교 및 정렬 및 같음 테스트에 대한 작업은 서수 또는 문화권에 민감할 수 있습니다. 다음 섹션에서는 각 작업 범주에 대해 설명합니다.
팁
항상 메서드 호출의 의도를 명확하게 하는 메서드 오버로드를 호출해야 합니다. 예를 들어 현재 문화권의 규칙을 사용하여 두 문자열의 문화권 구분 비교를 수행하도록 메서드를 호출 Compare(String, String) 하는 대신 인수 값 StringComparison.CurrentCulture comparisonType
이 있는 메서드를 호출 Compare(String, String, StringComparison) 해야 합니다. 자세한 내용은 문자열 사용에 대한 모범 사례를 참조하세요.
정렬 및 비교 작업에 사용되는 문자 가중치에 대한 정보가 포함된 텍스트 파일 집합인 정렬 가중치 테이블을 다음 링크에서 다운로드할 수 있습니다.
- Windows(.NET Framework 및 .NET Core): 가중치 테이블 정렬
- Windows 10 2019년 5월 업데이트 이상(.NET 5 이상) 및 Linux 및 macOS(.NET Core 및 .NET 5 이상): 기본 유니코드 데이터 정렬 요소 테이블
대/소문자 구분
대/소문자 규칙은 유니코드 문자의 대문자를 변경하는 방법을 결정합니다. 예를 들어 소문자에서 대문자로 변환합니다. 대/소문자 구분 연산은 문자열 비교 전에 수행되는 경우가 많습니다. 예를 들어 문자열을 대문자로 변환하여 다른 대문자 문자열과 비교할 수 있습니다. 또는 ToLowerInvariant 메서드를 호출 ToLower 하여 문자열의 문자를 소문자로 변환할 수 있으며 또는 메서드를 호출 ToUpper ToUpperInvariant 하여 대문자로 변환할 수 있습니다. 또한 메서드를 사용하여 문자열을 TextInfo.ToTitleCase 제목 대/소문자로 변환할 수 있습니다.
참고 항목
Linux 및 macOS 시스템에서만 실행되는 .NET Core: C 및 Posix 문화권에 대한 데이터 정렬 동작은 이러한 문화권에서 예상되는 유니코드 데이터 정렬 순서를 사용하지 않으므로 항상 대/소문자를 구분합니다. C 또는 Posix 이외의 문화권을 사용하여 문화권 구분, 대/소문자 비구분 정렬 작업을 수행하는 것이 좋습니다.
대/소문자 연산은 현재 문화권, 지정된 문화권 또는 고정 문화권의 규칙을 기반으로 할 수 있습니다. 대/소문자 매핑은 사용되는 문화권에 따라 달라질 수 있으므로 대/소문자 연산의 결과는 문화권에 따라 달라질 수 있습니다. 대/소문자의 실제 차이점은 세 가지 종류입니다.
라틴 문자 I(U+0049), LATIN SMALL LETTER I(U+0069), LATIN CAPITAL LETTER I WITH DOT ABOVE(U+0130) 및 LATIN SMALL LETTER DOTLESS I(U+0131)의 사례 매핑의 차이점입니다. tr-TR(터키어(터키)) 및 az-Latn-AZ(아제르바이잔, 라틴어) 문화권 및 tr, az 및 az-Latn 중립 문화권에서는 LATIN CAPITAL LETTER I의 소문자 I는 LATIN SMALL LETTER DOTLESS I이고 라틴어 SMALL LETTER I의 대문자로는 라틴 문자 I WITH DOT ABOVE입니다. 고정 문화권, LATIN SMALL LETTER I 및 LATIN CAPITAL LETTER I를 포함한 다른 모든 문화권에서는 소문자 및 대문자 등가물입니다.
다음 예제에서는 문화권 구분 대/소문자 비교를 사용하는 경우 파일 시스템 액세스를 방지하기 위해 설계된 문자열 비교가 실패할 수 있는 방법을 보여 줍니다. 고정 문화권의 대/소문자 구분 규칙을 사용해야 합니다.
using System; using System.Globalization; using System.Threading; public class Example1 { const string disallowed = "file"; public static void Main() { IsAccessAllowed(@"FILE:\\\c:\users\user001\documents\FinancialInfo.txt"); } private static void IsAccessAllowed(String resource) { CultureInfo[] cultures = { CultureInfo.CreateSpecificCulture("en-US"), CultureInfo.CreateSpecificCulture("tr-TR") }; String scheme = null; int index = resource.IndexOfAny( new Char[] { '\\', '/' } ); if (index > 0) scheme = resource.Substring(0, index - 1); // Change the current culture and perform the comparison. foreach (var culture in cultures) { Thread.CurrentThread.CurrentCulture = culture; Console.WriteLine("Culture: {0}", CultureInfo.CurrentCulture.DisplayName); Console.WriteLine(resource); Console.WriteLine("Access allowed: {0}", ! String.Equals(disallowed, scheme, StringComparison.CurrentCultureIgnoreCase)); Console.WriteLine(); } } } // The example displays the following output: // Culture: English (United States) // FILE:\\\c:\users\user001\documents\FinancialInfo.txt // Access allowed: False // // Culture: Turkish (Turkey) // FILE:\\\c:\users\user001\documents\FinancialInfo.txt // Access allowed: True
open System open System.Globalization open System.Threading let disallowed = "file" let isAccessAllowed (resource: string) = let cultures = [| CultureInfo.CreateSpecificCulture "en-US" CultureInfo.CreateSpecificCulture "tr-TR" |] let index = resource.IndexOfAny [| '\\'; '/' |] let scheme = if index > 0 then resource.Substring(0, index - 1) else null // Change the current culture and perform the comparison. for culture in cultures do Thread.CurrentThread.CurrentCulture <- culture printfn $"Culture: {CultureInfo.CurrentCulture.DisplayName}" printfn $"{resource}" printfn $"Access allowed: {String.Equals(disallowed, scheme, StringComparison.CurrentCultureIgnoreCase) |> not}" printfn "" isAccessAllowed @"FILE:\\\c:\users\user001\documents\FinancialInfo.txt" // The example displays the following output: // Culture: English (United States) // FILE:\\\c:\users\user001\documents\FinancialInfo.txt // Access allowed: False // // Culture: Turkish (Turkey) // FILE:\\\c:\users\user001\documents\FinancialInfo.txt // Access allowed: True
Imports System.Globalization Imports System.Threading Module Example2 Const disallowed = "file" Public Sub Main() IsAccessAllowed("FILE:\\\c:\users\user001\documents\FinancialInfo.txt") End Sub Private Sub IsAccessAllowed(resource As String) Dim cultures() As CultureInfo = {CultureInfo.CreateSpecificCulture("en-US"), CultureInfo.CreateSpecificCulture("tr-TR")} Dim scheme As String = Nothing Dim index As Integer = resource.IndexOfAny({"\"c, "/"c}) If index > 0 Then scheme = resource.Substring(0, index - 1) ' Change the current culture and perform the comparison. For Each culture In cultures Thread.CurrentThread.CurrentCulture = culture Console.WriteLine("Culture: {0}", CultureInfo.CurrentCulture.DisplayName) Console.WriteLine(resource) Console.WriteLine("Access allowed: {0}", Not String.Equals(disallowed, scheme, StringComparison.CurrentCultureIgnoreCase)) Console.WriteLine() Next End Sub End Module ' The example displays the following output: ' Culture: English (United States) ' FILE:\\\c:\users\user001\documents\FinancialInfo.txt ' Access allowed: False ' ' Culture: Turkish (Turkey) ' FILE:\\\c:\users\user001\documents\FinancialInfo.txt ' Access allowed: True
고정 문화권과 다른 모든 문화권 간의 대/소문자 매핑의 차이입니다. 이러한 경우 고정 문화권의 대/소문자 규칙을 사용하여 문자를 대문자 또는 소문자로 변경하면 동일한 문자가 반환됩니다. 다른 모든 문화권의 경우 다른 문자를 반환합니다. 영향을 받는 문자 중 일부는 다음 표에 나와 있습니다.
캐릭터 다음으로 변경된 경우 반품 MICRON SIGN(U+00B5) 대문자 그리스어 대문자 MU(U+-39C) 위에 점이 있는 라틴 문자 I(U+0130) 소문자 라틴 문자 I(U+0069) LATIN SMALL LETTER DOTLESS I(U+0131) 대문자 라틴 문자 I(U+0049) LATIN SMALL LETTER LONG S(U+017F) 대문자 라틴 문자 S(U+0053) CARON이 있는 작은 문자 Z가 있는 라틴 문자 D(U+01C5) 소문자 CARON을 사용하여 라틴 문자 DZ(U+01C6) 그리스어 YPOGEGRAMMENI 결합(U+0345) 대문자 그리스어 대문자 IOTA(U+0399) ASCII 문자 범위에서 두 문자 혼합 대/소문자 쌍의 대/소문자 매핑의 차이점입니다. 대부분의 문화권에서 두 문자 혼합 대/소문자 쌍은 해당하는 2자 대문자 또는 소문자 쌍과 같습니다. 각 경우에 digraph와 비교되기 때문에 다음 문화권에서 다음 두 문자 쌍에 대해서는 그렇지 않습니다.
- hr-HR(크로아티아어(크로아티아) 문화권의 "lJ" 및 "nJ"입니다.
- cs-CZ(체코)와 sk-SK(슬로바키아)의 "cH".
- da-DK(덴마크어(덴마크)) 문화권의 "aA".
- hu-HU(헝가리어)의 문화권에서 "cS", "dZ", "dZS", "nY", "sZ", "tY" 및 "zS"입니다.
- es-ES_tradnl(스페인, 전통 정렬) 문화권의 "cH" 및 "lL"입니다.
- vi-VN(베트남어)의 "cH", "gI", "kH", "nG" "nH", "pH", "qU', "tH" 및 "tR"입니다.
그러나 이러한 쌍은 고정 문자열 또는 식별자에서 일반적이지 않으므로 이러한 쌍의 문화권 구분 비교로 인해 문제가 발생하는 경우는 이례적인 일입니다.
다음 예제에서는 문자열을 대문자로 변환할 때 문화권 간의 대/소문자 구분 규칙의 몇 가지 차이점을 보여 줍니다.
using System;
using System.Globalization;
using System.IO;
public class Example
{
public static void Main()
{
StreamWriter sw = new StreamWriter(@".\case.txt");
string[] words = { "file", "sıfır", "Dženana" };
CultureInfo[] cultures = { CultureInfo.InvariantCulture,
new CultureInfo("en-US"),
new CultureInfo("tr-TR") };
foreach (var word in words) {
sw.WriteLine("{0}:", word);
foreach (var culture in cultures) {
string name = String.IsNullOrEmpty(culture.Name) ?
"Invariant" : culture.Name;
string upperWord = word.ToUpper(culture);
sw.WriteLine(" {0,10}: {1,7} {2, 38}", name,
upperWord, ShowHexValue(upperWord));
}
sw.WriteLine();
}
sw.Close();
}
private static string ShowHexValue(string s)
{
string retval = null;
foreach (var ch in s) {
byte[] bytes = BitConverter.GetBytes(ch);
retval += String.Format("{0:X2} {1:X2} ", bytes[1], bytes[0]);
}
return retval;
}
}
// The example displays the following output:
// file:
// Invariant: FILE 00 46 00 49 00 4C 00 45
// en-US: FILE 00 46 00 49 00 4C 00 45
// tr-TR: FİLE 00 46 01 30 00 4C 00 45
//
// sıfır:
// Invariant: SıFıR 00 53 01 31 00 46 01 31 00 52
// en-US: SIFIR 00 53 00 49 00 46 00 49 00 52
// tr-TR: SIFIR 00 53 00 49 00 46 00 49 00 52
//
// Dženana:
// Invariant: DžENANA 01 C5 00 45 00 4E 00 41 00 4E 00 41
// en-US: DŽENANA 01 C4 00 45 00 4E 00 41 00 4E 00 41
// tr-TR: DŽENANA 01 C4 00 45 00 4E 00 41 00 4E 00 41
open System
open System.Globalization
open System.IO
let showHexValue (s: string) =
let mutable retval = ""
for ch in s do
let bytes = BitConverter.GetBytes ch
retval <- retval + String.Format("{0:X2} {1:X2} ", bytes[1], bytes[0])
retval
do
use sw = new StreamWriter(@".\case.txt")
let words = [| "file"; "sıfır"; "Dženana" |]
let cultures =
[| CultureInfo.InvariantCulture
CultureInfo "en-US"
CultureInfo "tr-TR" |]
for word in words do
sw.WriteLine("{0}:", word)
for culture in cultures do
let name =
if String.IsNullOrEmpty culture.Name then "Invariant" else culture.Name
let upperWord = word.ToUpper culture
sw.WriteLine(" {0,10}: {1,7} {2, 38}", name, upperWord, showHexValue upperWord)
sw.WriteLine()
sw.Close()
// The example displays the following output:
// file:
// Invariant: FILE 00 46 00 49 00 4C 00 45
// en-US: FILE 00 46 00 49 00 4C 00 45
// tr-TR: FİLE 00 46 01 30 00 4C 00 45
//
// sıfır:
// Invariant: SıFıR 00 53 01 31 00 46 01 31 00 52
// en-US: SIFIR 00 53 00 49 00 46 00 49 00 52
// tr-TR: SIFIR 00 53 00 49 00 46 00 49 00 52
//
// Dženana:
// Invariant: DžENANA 01 C5 00 45 00 4E 00 41 00 4E 00 41
// en-US: DŽENANA 01 C4 00 45 00 4E 00 41 00 4E 00 41
// tr-TR: DŽENANA 01 C4 00 45 00 4E 00 41 00 4E 00 41
Imports System.Globalization
Imports System.IO
Module Example1
Public Sub Main()
Dim sw As New StreamWriter(".\case.txt")
Dim words As String() = {"file", "sıfır", "Dženana"}
Dim cultures() As CultureInfo = {CultureInfo.InvariantCulture,
New CultureInfo("en-US"),
New CultureInfo("tr-TR")}
For Each word In words
sw.WriteLine("{0}:", word)
For Each culture In cultures
Dim name As String = If(String.IsNullOrEmpty(culture.Name),
"Invariant", culture.Name)
Dim upperWord As String = word.ToUpper(culture)
sw.WriteLine(" {0,10}: {1,7} {2, 38}", name,
upperWord, ShowHexValue(upperWord))
Next
sw.WriteLine()
Next
sw.Close()
End Sub
Private Function ShowHexValue(s As String) As String
Dim retval As String = Nothing
For Each ch In s
Dim bytes() As Byte = BitConverter.GetBytes(ch)
retval += String.Format("{0:X2} {1:X2} ", bytes(1), bytes(0))
Next
Return retval
End Function
End Module
' The example displays the following output:
' file:
' Invariant: FILE 00 46 00 49 00 4C 00 45
' en-US: FILE 00 46 00 49 00 4C 00 45
' tr-TR: FİLE 00 46 01 30 00 4C 00 45
'
' sıfır:
' Invariant: SıFıR 00 53 01 31 00 46 01 31 00 52
' en-US: SIFIR 00 53 00 49 00 46 00 49 00 52
' tr-TR: SIFIR 00 53 00 49 00 46 00 49 00 52
'
' Dženana:
' Invariant: DžENANA 01 C5 00 45 00 4E 00 41 00 4E 00 41
' en-US: DŽENANA 01 C4 00 45 00 4E 00 41 00 4E 00 41
' tr-TR: DŽENANA 01 C4 00 45 00 4E 00 41 00 4E 00 41
구문 분석 및 서식 지정
서식 지정 및 구문 분석은 역 연산입니다. 서식 지정 규칙은 날짜, 시간 또는 숫자와 같은 값을 해당 문자열 표현으로 변환하는 방법을 결정하는 반면 구문 분석 규칙은 문자열 표현을 날짜 및 시간과 같은 값으로 변환하는 방법을 결정합니다. 서식 지정 및 구문 분석 규칙은 모두 문화권 규칙에 따라 달라집니다. 다음 예제에서는 문화권별 날짜 문자열을 해석할 때 발생할 수 있는 모호성을 보여 줍니다. 날짜 문자열을 생성하는 데 사용된 문화권의 규칙을 알지 못하면 2011년 3월 1일, 2011년 3월 1일 및 2011년 1월 3일 또는 2011년 3월 1일을 나타내는지 여부를 알 수 없습니다.
using System;
using System.Globalization;
public class Example9
{
public static void Main()
{
DateTime date = new DateTime(2011, 3, 1);
CultureInfo[] cultures = { CultureInfo.InvariantCulture,
new CultureInfo("en-US"),
new CultureInfo("fr-FR") };
foreach (var culture in cultures)
Console.WriteLine("{0,-12} {1}", String.IsNullOrEmpty(culture.Name) ?
"Invariant" : culture.Name,
date.ToString("d", culture));
}
}
// The example displays the following output:
// Invariant 03/01/2011
// en-US 3/1/2011
// fr-FR 01/03/2011
open System
open System.Globalization
let date = DateTime(2011, 3, 1)
let cultures =
[| CultureInfo.InvariantCulture
CultureInfo "en-US"
CultureInfo "fr-FR" |]
for culture in cultures do
printfn $"""{(if String.IsNullOrEmpty culture.Name then "Invariant" else culture.Name),-12} {date.ToString("d", culture)}"""
// The example displays the following output:
// Invariant 03/01/2011
// en-US 3/1/2011
// fr-FR 01/03/2011
Imports System.Globalization
Module Example8
Public Sub Main()
Dim dat As Date = #3/1/2011#
Dim cultures() As CultureInfo = {CultureInfo.InvariantCulture,
New CultureInfo("en-US"),
New CultureInfo("fr-FR")}
For Each culture In cultures
Console.WriteLine("{0,-12} {1}", If(String.IsNullOrEmpty(culture.Name),
"Invariant", culture.Name),
dat.ToString("d", culture))
Next
End Sub
End Module
' The example displays the following output:
' Invariant 03/01/2011
' en-US 3/1/2011
' fr-FR 01/03/2011
마찬가지로, 다음 예제와 같이 단일 문자열은 구문 분석 작업에 규칙이 사용되는 문화권에 따라 다른 날짜를 생성할 수 있습니다.
using System;
using System.Globalization;
public class Example15
{
public static void Main()
{
string dateString = "07/10/2011";
CultureInfo[] cultures = { CultureInfo.InvariantCulture,
CultureInfo.CreateSpecificCulture("en-GB"),
CultureInfo.CreateSpecificCulture("en-US") };
Console.WriteLine("{0,-12} {1,10} {2,8} {3,8}\n", "Date String", "Culture",
"Month", "Day");
foreach (var culture in cultures) {
DateTime date = DateTime.Parse(dateString, culture);
Console.WriteLine("{0,-12} {1,10} {2,8} {3,8}", dateString,
String.IsNullOrEmpty(culture.Name) ?
"Invariant" : culture.Name,
date.Month, date.Day);
}
}
}
// The example displays the following output:
// Date String Culture Month Day
//
// 07/10/2011 Invariant 7 10
// 07/10/2011 en-GB 10 7
// 07/10/2011 en-US 7 10
open System
open System.Globalization
let dateString = "07/10/2011"
let cultures =
[| CultureInfo.InvariantCulture
CultureInfo.CreateSpecificCulture "en-GB"
CultureInfo.CreateSpecificCulture "en-US" |]
printfn $"""{"Date String",-12} {"Culture",10} {"Month",8} {"Day",8}\n"""
for culture in cultures do
let date = DateTime.Parse(dateString, culture)
printfn $"""{dateString,-12} {(if String.IsNullOrEmpty culture.Name then "Invariant" else culture.Name),10} {date.Month,8} {date.Day,8}"""
// The example displays the following output:
// Date String Culture Month Day
//
// 07/10/2011 Invariant 7 10
// 07/10/2011 en-GB 10 7
// 07/10/2011 en-US 7 10
Imports System.Globalization
Module Example18
Public Sub Main()
Dim dateString As String = "07/10/2011"
Dim cultures() As CultureInfo = {CultureInfo.InvariantCulture,
CultureInfo.CreateSpecificCulture("en-GB"),
CultureInfo.CreateSpecificCulture("en-US")}
Console.WriteLine("{0,-12} {1,10} {2,8} {3,8}", "Date String", "Culture",
"Month", "Day")
Console.WriteLine()
For Each culture In cultures
Dim dat As Date = DateTime.Parse(dateString, culture)
Console.WriteLine("{0,-12} {1,10} {2,8} {3,8}", dateString,
If(String.IsNullOrEmpty(culture.Name),
"Invariant", culture.Name),
dat.Month, dat.Day)
Next
End Sub
End Module
' The example displays the following output:
' Date String Culture Month Day
'
' 07/10/2011 Invariant 7 10
' 07/10/2011 en-GB 10 7
' 07/10/2011 en-US 7 10
문자열 비교 및 정렬
문자열을 비교하고 정렬하는 규칙은 문화권마다 다릅니다. 예를 들어 정렬 순서는 윗주 또는 문자의 시각적 표현을 기반으로 할 수 있습니다. 동아시아 언어에서는 표의 문자의 부수와 획에 따라 문자가 정렬됩니다. 언어와 문화권이 알파벳에 사용하는 순서에 따라 정렬 순서가 달라지기도 합니다. 예를 들어 덴마크어 알파벳의 "Æ" 문자는 "Z" 다음에 옵니다. 또한 비교는 대/소문자를 구분하거나 대/소문자를 구분하지 않을 수 있으며 대/소문자 구분 규칙은 문화권에 따라 다를 수 있습니다. 반면 서수 비교는 문자열을 비교하고 정렬할 때 문자열에 있는 개별 문자의 유니코드 코드 요소를 사용합니다.
정렬 규칙은 유니코드 문자의 알파벳 순서와 두 문자열이 서로 비교되는 방식을 결정합니다. 예를 들어 메서드는 String.Compare(String, String, StringComparison) 매개 변수를 기반으로 두 문자열을 StringComparison 비교합니다. 매개 변수 값이면 메서드는 StringComparison.CurrentCulture현재 문화권의 규칙을 사용하는 언어 비교를 수행합니다. 매개 변수 값이 StringComparison.Ordinal면 메서드가 서수 비교를 수행합니다. 따라서 다음 예제에서 볼 수 있듯이 현재 문화권이 미국 영어인 경우 메서드에 대한 첫 번째 호출 String.Compare(String, String, StringComparison) (문화권 구분 비교 사용)은 "a"가 "A"보다 작지만 동일한 메서드(서수 비교 사용)에 대한 두 번째 호출은 "A"보다 큰 "a"를 고려합니다.
using System;
using System.Globalization;
using System.Threading;
public class Example2
{
public static void Main()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
Console.WriteLine(String.Compare("A", "a", StringComparison.CurrentCulture));
Console.WriteLine(String.Compare("A", "a", StringComparison.Ordinal));
}
}
// The example displays the following output:
// 1
// -32
open System
open System.Globalization
open System.Threading
Thread.CurrentThread.CurrentCulture <- CultureInfo.CreateSpecificCulture "en-US"
printfn $"""{String.Compare("A", "a", StringComparison.CurrentCulture)}"""
printfn $"""{String.Compare("A", "a", StringComparison.Ordinal)}"""
// The example displays the following output:
// 1
// -32
Imports System.Globalization
Imports System.Threading
Module Example3
Public Sub Main()
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US")
Console.WriteLine(String.Compare("A", "a", StringComparison.CurrentCulture))
Console.WriteLine(String.Compare("A", "a", StringComparison.Ordinal))
End Sub
End Module
' The example displays the following output:
' 1
' -32
.NET은 단어, 문자열 및 서수 정렬 규칙을 지원합니다.
단어 정렬은 특정 무수 유니코드 문자에 특수 가중치가 할당될 수 있는 문자열의 문화권 구분 비교를 수행합니다. 예를 들어 하이픈(-)에는 매우 작은 가중치가 할당되어 정렬된 목록에서 "coop" 및 "co-op"이 나란히 표시될 수 있습니다. 단어 정렬 규칙을 사용하여 두 문자열을 비교하는 메서드 목록은 String 범주별 문자열 연산 섹션을 참조하세요.
문자열 정렬은 문화권 구분 비교도 수행합니다. 특수한 경우가 없고 모든 영숫자가 아닌 기호가 모든 영숫자 유니코드 문자 앞에 온다는 점을 제외하고 단어 정렬과 유사합니다. 값CompareOptions.StringSort이 제공된 매개 변수가 있는 메서드 오버로드
options
를 호출 CompareInfo.Compare 하여 문자열 정렬 규칙을 사용하여 두 문자열을 비교할 수 있습니다. 문자열 정렬 규칙을 사용하여 두 문자열을 비교하기 위해 .NET에서 제공하는 유일한 메서드입니다.서수 정렬은 문자열에 있는 각 Char 개체의 숫자 값을 기준으로 문자열을 비교합니다. 서수 비교는 문자의 소문자 및 대문자 버전에 다른 코드 포인트가 있기 때문에 자동으로 대/소문자를 구분합니다. 그러나 대/소문자를 중요하지 않은 경우 대/소문자를 무시하는 서수 비교를 지정할 수 있습니다. 이는 고정 문화권을 사용한 다음 결과에 대한 서수 비교를 수행하여 문자열을 대문자로 변환하는 것과 같습니다. 서수 정렬 규칙을 사용하여 두 문자열을 비교하는 메서드 목록은 String 범주별 문자열 작업을 참조하세요.
문화권 구분 비교는 속성에 지정된 CultureInfo.InvariantCulture 고정 문화권을 포함하여 개체를 CultureInfo 명시적으로 또는 암시적으로 사용하는 비교입니다. 암시적 문화권은 현재 문화권이며, 이 문화권은 및 CultureInfo.CurrentCulture 속성에 Thread.CurrentCulture 의해 지정됩니다. 문화권 간에 알파벳 문자의 정렬 순서(즉, 속성이 반환true
하는 Char.IsLetter 문자)에 상당한 변형이 있습니다. 같은 문자열 비교 메서드Compare(String, String, CultureInfo, CompareOptions)에 개체를 제공하여 CultureInfo 특정 문화권의 규칙을 사용하는 문화권 구분 비교를 지정할 수 있습니다. 메서드의 적절한 오버로드 Compare 가 아닌 CompareOptions.OrdinalIgnoreCase CompareOptions.Ordinal 열거형의 멤버를 제공하여 StringComparison.CurrentCultureStringComparison.CurrentCultureIgnoreCase현재 문화권의 CompareOptions 규칙을 사용하는 문화권 구분 비교를 지정할 수 있습니다. 문화권 구분 비교는 일반적으로 정렬에 적합하지만 서수 비교는 그렇지 않습니다. 서수 비교는 일반적으로 두 문자열이 같은지(즉, ID를 결정하기 위해) 결정하는 데 적합하지만 문화권 구분 비교는 그렇지 않습니다.
다음 예제에서는 문화권 구분과 서수 비교의 차이를 보여 줍니다. 이 예제에서는 da-DK 및 en-US 문화권의 서수 비교 및 규칙(각각 메서드가 호출되는 시점 Compare 의 기본 문화권)을 사용하여 세 개의 문자열인 "Apple", "Æble" 및 "AEble"을 평가합니다. 덴마크어 언어는 문자 "Æ"를 개별 문자로 취급하고 알파벳의 "Z" 뒤를 정렬하기 때문에 문자열 "Æble"은 "Apple"보다 큽니다. 그러나 "Æble"은 "AEble"에 해당하는 것으로 간주되지 않으므로 "Æble"도 "AEble"보다 큽니다. en-US 문화권에는 문자 "Æ"가 포함되지 않지만 "Æble"이 "Apple"보다 작지만 "AEble"이 같은 이유를 설명하는 "AE"와 동일하게 처리됩니다. 반면 서수 비교에서는 "Apple"이 "Æble"보다 작고 "Æble"이 "AEble"보다 큰 것으로 간주합니다.
using System;
using System.Globalization;
using System.Threading;
public class CompareStringSample
{
public static void Main()
{
string str1 = "Apple";
string str2 = "Æble";
string str3 = "AEble";
// Set the current culture to Danish in Denmark.
Thread.CurrentThread.CurrentCulture = new CultureInfo("da-DK");
Console.WriteLine("Current culture: {0}",
CultureInfo.CurrentCulture.Name);
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2, String.Compare(str1, str2));
Console.WriteLine("Comparison of {0} with {1}: {2}\n",
str2, str3, String.Compare(str2, str3));
// Set the current culture to English in the U.S.
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Console.WriteLine("Current culture: {0}",
CultureInfo.CurrentCulture.Name);
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2, String.Compare(str1, str2));
Console.WriteLine("Comparison of {0} with {1}: {2}\n",
str2, str3, String.Compare(str2, str3));
// Perform an ordinal comparison.
Console.WriteLine("Ordinal comparison");
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2,
String.Compare(str1, str2, StringComparison.Ordinal));
Console.WriteLine("Comparison of {0} with {1}: {2}",
str2, str3,
String.Compare(str2, str3, StringComparison.Ordinal));
}
}
// The example displays the following output:
// Current culture: da-DK
// Comparison of Apple with Æble: -1
// Comparison of Æble with AEble: 1
//
// Current culture: en-US
// Comparison of Apple with Æble: 1
// Comparison of Æble with AEble: 0
//
// Ordinal comparison
// Comparison of Apple with Æble: -133
// Comparison of Æble with AEble: 133
open System
open System.Globalization
open System.Threading
let str1 = "Apple"
let str2 = "Æble"
let str3 = "AEble"
// Set the current culture to Danish in Denmark.
Thread.CurrentThread.CurrentCulture <- CultureInfo "da-DK"
printfn $"Current culture: {CultureInfo.CurrentCulture.Name}"
printfn $"Comparison of {str1} with {str2}: {String.Compare(str1, str2)}"
printfn $"Comparison of {str2} with {str3}: {String.Compare(str2, str3)}\n"
// Set the current culture to English in the U.S.
Thread.CurrentThread.CurrentCulture <- CultureInfo "en-US"
printfn $"Current culture: {CultureInfo.CurrentCulture.Name}"
printfn $"Comparison of {str1} with {str2}: {String.Compare(str1, str2)}"
printfn $"Comparison of {str2} with {str3}: {String.Compare(str2, str3)}\n"
// Perform an ordinal comparison.
printfn "Ordinal comparison"
printfn $"Comparison of {str1} with {str2}: {String.Compare(str1, str2, StringComparison.Ordinal)}"
printfn $"Comparison of {str2} with {str3}: {String.Compare(str2, str3, StringComparison.Ordinal)}"
// The example displays the following output:
// Current culture: da-DK
// Comparison of Apple with Æble: -1
// Comparison of Æble with AEble: 1
//
// Current culture: en-US
// Comparison of Apple with Æble: 1
// Comparison of Æble with AEble: 0
//
// Ordinal comparison
// Comparison of Apple with Æble: -133
// Comparison of Æble with AEble: 133
Imports System.Globalization
Imports System.Threading
Public Module Example6
Public Sub Main()
Dim str1 As String = "Apple"
Dim str2 As String = "Æble"
Dim str3 As String = "AEble"
' Set the current culture to Danish in Denmark.
Thread.CurrentThread.CurrentCulture = New CultureInfo("da-DK")
Console.WriteLine("Current culture: {0}",
CultureInfo.CurrentCulture.Name)
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2, String.Compare(str1, str2))
Console.WriteLine("Comparison of {0} with {1}: {2}",
str2, str3, String.Compare(str2, str3))
Console.WriteLine()
' Set the current culture to English in the U.S.
Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
Console.WriteLine("Current culture: {0}",
CultureInfo.CurrentCulture.Name)
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2, String.Compare(str1, str2))
Console.WriteLine("Comparison of {0} with {1}: {2}",
str2, str3, String.Compare(str2, str3))
Console.WriteLine()
' Perform an ordinal comparison.
Console.WriteLine("Ordinal comparison")
Console.WriteLine("Comparison of {0} with {1}: {2}",
str1, str2,
String.Compare(str1, str2, StringComparison.Ordinal))
Console.WriteLine("Comparison of {0} with {1}: {2}",
str2, str3,
String.Compare(str2, str3, StringComparison.Ordinal))
End Sub
End Module
' The example displays the following output:
' Current culture: da-DK
' Comparison of Apple with Æble: -1
' Comparison of Æble with AEble: 1
'
' Current culture: en-US
' Comparison of Apple with Æble: 1
' Comparison of Æble with AEble: 0
'
' Ordinal comparison
' Comparison of Apple with Æble: -133
' Comparison of Æble with AEble: 133
적절한 정렬 또는 문자열 비교 방법을 선택하려면 다음 일반 지침을 사용합니다.
사용자의 문화권에 따라 문자열을 정렬하려면 현재 문화권의 규칙에 따라 순서를 지정해야 합니다. 사용자의 문화권이 변경되면 정렬된 문자열의 순서도 그에 따라 변경됩니다. 예를 들어 동의어 사전 애플리케이션을 사용자의 문화권을 기준으로 단어를 항상 정렬 해야 합니다.
특정 문화권의 규칙에 따라 문자열을 정렬하려면 해당 문화권을 나타내는 개체를 CultureInfo 비교 메서드에 제공하여 순서를 지정해야 합니다. 예를 들어, 학생에 게 특정 언어를 설명 하도록 애플리케이션에서 원하는 문자열을 정렬할 익히면 해당 하는 문화권 중 하나로의 규칙에 따라 합니다.
문자열 순서가 문화권 간에 변경되지 않은 상태로 유지되도록 하려면 고정 문화권의 규칙에 따라 순서를 지정하거나 서수 비교를 사용해야 합니다. 예를 들어 서수 정렬을 사용하여 파일, 프로세스, 뮤텍스 또는 명명된 파이프의 이름을 구성합니다.
보안 결정(예: 사용자 이름이 유효한지 여부)을 포함하는 비교의 경우 메서드의 Equals 오버로드를 호출하여 항상 같음 서수 테스트를 수행해야 합니다.
참고 항목
문자열 비교에 사용되는 문화권 구분 정렬 및 대/소문자 규칙은 .NET 버전에 따라 달라집니다. .NET Core에서 문자열 비교는 기본 운영 체제에서 지원하는 유니코드 표준의 버전에 따라 달라집니다. Windows 8 이상에서 실행되는 .NET Framework 4.5 이상 버전에서는 정렬, 대/소문자, 정규화 및 유니코드 문자 정보가 유니코드 6.0 표준을 준수합니다. 다른 Windows 운영 체제에서는 유니코드 5.0 표준을 준수합니다.
단어, 문자열 및 서수 정렬 규칙에 대한 자세한 내용은 항목을 참조하세요 System.Globalization.CompareOptions . 각 규칙을 사용하는 경우에 대한 추가 권장 사항은 문자열 사용에 대한 모범 사례를 참조 하세요.
일반적으로 문자열의 정렬 순서를 확인하기 위해 직접 같은 Compare 문자열 비교 메서드를 호출하지 않습니다. 대신 비교 메서드는 다음과 같은 Array.Sort 메서드를 정렬하여 호출됩니다 List<T>.Sort. 다음 예제에서는 문자열 비교 메서드를 명시적으로 호출하지 않고 네 가지 정렬 작업(현재 문화권을 사용하여 단어 정렬, 고정 문화권을 사용한 단어 정렬, 서수 정렬 및 문자열 정렬)을 수행하지만 사용할 비교 형식을 지정합니다. 정렬의 각 형식은 배열에서 문자열의 고유한 순서를 생성합니다.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
public class Example3
{
public static void Main()
{
string[] strings = { "coop", "co-op", "cooperative",
"co\u00ADoperative", "cœur", "coeur" };
// Perform a word sort using the current (en-US) culture.
string[] current = new string[strings.Length];
strings.CopyTo(current, 0);
Array.Sort(current, StringComparer.CurrentCulture);
// Perform a word sort using the invariant culture.
string[] invariant = new string[strings.Length];
strings.CopyTo(invariant, 0);
Array.Sort(invariant, StringComparer.InvariantCulture);
// Perform an ordinal sort.
string[] ordinal = new string[strings.Length];
strings.CopyTo(ordinal, 0);
Array.Sort(ordinal, StringComparer.Ordinal);
// Perform a string sort using the current culture.
string[] stringSort = new string[strings.Length];
strings.CopyTo(stringSort, 0);
Array.Sort(stringSort, new SCompare());
// Display array values
Console.WriteLine("{0,13} {1,13} {2,15} {3,13} {4,13}\n",
"Original", "Word Sort", "Invariant Word",
"Ordinal Sort", "String Sort");
for (int ctr = 0; ctr < strings.Length; ctr++)
Console.WriteLine("{0,13} {1,13} {2,15} {3,13} {4,13}",
strings[ctr], current[ctr], invariant[ctr],
ordinal[ctr], stringSort[ctr] );
}
}
// IComparer<String> implementation to perform string sort.
internal class SCompare : IComparer<String>
{
public int Compare(string x, string y)
{
return CultureInfo.CurrentCulture.CompareInfo.Compare(x, y, CompareOptions.StringSort);
}
}
// The example displays the following output:
// Original Word Sort Invariant Word Ordinal Sort String Sort
//
// coop cœur cœur co-op co-op
// co-op coeur coeur coeur cœur
// cooperative coop coop coop coeur
// cooperative co-op co-op cooperative coop
// cœur cooperative cooperative cooperative cooperative
// coeur cooperative cooperative cœur cooperative
open System
open System.Collections.Generic
open System.Globalization
// IComparer<String> implementation to perform string sort using an F# object expression.
let scompare =
{ new IComparer<String> with
member _.Compare(x, y) =
CultureInfo.CurrentCulture.CompareInfo.Compare(x, y, CompareOptions.StringSort) }
let strings = [| "coop"; "co-op"; "cooperative"; "co\u00ADoperative"; "cœur"; "coeur" |]
// Perform a word sort using the current (en-US) culture.
let current = Array.copy strings
Array.Sort(current, StringComparer.CurrentCulture)
// Perform a word sort using the invariant culture.
let invariant = Array.copy strings
Array.Sort(invariant, StringComparer.InvariantCulture)
// Perform an ordinal sort.
let ordinal = Array.copy strings
Array.Sort(ordinal, StringComparer.Ordinal)
// Perform a string sort using the current culture.
let stringSort = Array.copy strings
Array.Sort(stringSort, scompare)
// Display array values
printfn "%13s %13s %15s %13s %13s\n" "Original" "Word Sort" "Invariant Word" "Ordinal Sort" "String Sort"
for i = 0 to strings.Length - 1 do
printfn "%13s %13s %15s %13s %13s\n" strings[i] current[i] invariant[i] ordinal[i] stringSort[i]
// The example displays the following output:
// Original Word Sort Invariant Word Ordinal Sort String Sort
//
// coop cœur cœur co-op co-op
// co-op coeur coeur coeur cœur
// cooperative coop coop coop coeur
// cooperative co-op co-op cooperative coop
// cœur cooperative cooperative cooperative cooperative
// coeur cooperative cooperative cœur cooperative
Imports System.Collections
Imports System.Collections.Generic
Imports System.Globalization
Module Example4
Public Sub Main()
Dim strings() As String = {"coop", "co-op", "cooperative",
"co" + ChrW(&HAD) + "operative",
"cœur", "coeur"}
' Perform a word sort using the current (en-US) culture.
Dim current(strings.Length - 1) As String
strings.CopyTo(current, 0)
Array.Sort(current, StringComparer.CurrentCulture)
' Perform a word sort using the invariant culture.
Dim invariant(strings.Length - 1) As String
strings.CopyTo(invariant, 0)
Array.Sort(invariant, StringComparer.InvariantCulture)
' Perform an ordinal sort.
Dim ordinal(strings.Length - 1) As String
strings.CopyTo(ordinal, 0)
Array.Sort(ordinal, StringComparer.Ordinal)
' Perform a string sort using the current culture.
Dim stringSort(strings.Length - 1) As String
strings.CopyTo(stringSort, 0)
Array.Sort(stringSort, New SCompare())
' Display array values
Console.WriteLine("{0,13} {1,13} {2,15} {3,13} {4,13}",
"Original", "Word Sort", "Invariant Word",
"Ordinal Sort", "String Sort")
Console.WriteLine()
For ctr As Integer = 0 To strings.Length - 1
Console.WriteLine("{0,13} {1,13} {2,15} {3,13} {4,13}",
strings(ctr), current(ctr), invariant(ctr),
ordinal(ctr), stringSort(ctr))
Next
End Sub
End Module
' IComparer<String> implementation to perform string sort.
Friend Class SCompare : Implements IComparer(Of String)
Public Function Compare(x As String, y As String) As Integer _
Implements IComparer(Of String).Compare
Return CultureInfo.CurrentCulture.CompareInfo.Compare(x, y, CompareOptions.StringSort)
End Function
End Class
' The example displays the following output:
' Original Word Sort Invariant Word Ordinal Sort String Sort
'
' coop cœur cœur co-op co-op
' co-op coeur coeur coeur cœur
' cooperative coop coop coop coeur
' cooperative co-op co-op cooperative coop
' cœur cooperative cooperative cooperative cooperative
' coeur cooperative cooperative cœur cooperative
팁
내부적으로 .NET은 정렬 키를 사용하여 문화적으로 중요한 문자열 비교를 지원합니다. 문자열의 각 문자에는 사전순, 대/소문자 및 분음 부호를 포함하여 여러 범주의 정렬 가중치가 적용됩니다. 클래스가 SortKey 나타내는 정렬 키는 특정 문자열에 대해 이러한 가중치의 리포지토리를 제공합니다. 앱이 동일한 문자열 집합에서 많은 수의 검색 또는 정렬 작업을 수행하는 경우 사용하는 모든 문자열에 대한 정렬 키를 생성하고 저장하여 성능을 향상시킬 수 있습니다. 정렬 또는 비교 작업이 필요한 경우 문자열 대신 정렬 키를 사용합니다. 자세한 내용은 SortKey 클래스를 참조하세요.
문자열 비교 규칙을 지정하지 않으면 문자열에 대해 문화권을 구분하고 대/소문자를 구분하는 정렬을 수행하는 등의 Array.Sort(Array) 정렬 메서드가 있습니다. 다음 예제에서는 현재 문화권을 변경하면 배열에서 정렬된 문자열의 순서에 미치는 영향을 보여 줍니다. 세 문자열의 배열을 만듭니다. 우선 System.Threading.Thread.CurrentThread.CurrentCulture
속성을 "en-US"로 설정하고 Array.Sort(Array) 메서드를 호출합니다. 결과 정렬 순서는 영어(미국) 문화권에 대한 정렬 규칙을 기반으로 합니다. 다음으로 예제에서는 System.Threading.Thread.CurrentThread.CurrentCulture
속성을 da-DK로 설정하고 Array.Sort 메서드를 다시 호출합니다. 덴마크어(덴마크)의 정렬 규칙을 사용하는 경우 결과 정렬 순서가 en-US 결과와 어떻게 다른지 확인해 봅니다.
using System;
using System.Globalization;
using System.Threading;
public class ArraySort
{
public static void Main(String[] args)
{
// Create and initialize a new array to store the strings.
string[] stringArray = { "Apple", "Æble", "Zebra"};
// Display the values of the array.
Console.WriteLine( "The original string array:");
PrintIndexAndValues(stringArray);
// Set the CurrentCulture to "en-US".
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
// Sort the values of the array.
Array.Sort(stringArray);
// Display the values of the array.
Console.WriteLine("After sorting for the culture \"en-US\":");
PrintIndexAndValues(stringArray);
// Set the CurrentCulture to "da-DK".
Thread.CurrentThread.CurrentCulture = new CultureInfo("da-DK");
// Sort the values of the Array.
Array.Sort(stringArray);
// Display the values of the array.
Console.WriteLine("After sorting for the culture \"da-DK\":");
PrintIndexAndValues(stringArray);
}
public static void PrintIndexAndValues(string[] myArray)
{
for (int i = myArray.GetLowerBound(0); i <=
myArray.GetUpperBound(0); i++ )
Console.WriteLine("[{0}]: {1}", i, myArray[i]);
Console.WriteLine();
}
}
// The example displays the following output:
// The original string array:
// [0]: Apple
// [1]: Æble
// [2]: Zebra
//
// After sorting for the "en-US" culture:
// [0]: Æble
// [1]: Apple
// [2]: Zebra
//
// After sorting for the culture "da-DK":
// [0]: Apple
// [1]: Zebra
// [2]: Æble
open System
open System.Globalization
open System.Threading
let printIndexAndValues (myArray: string[]) =
for i = myArray.GetLowerBound 0 to myArray.GetUpperBound 0 do
printfn $"[{i}]: {myArray[i]}"
printfn ""
// Create and initialize a new array to store the strings.
let stringArray = [| "Apple"; "Æble"; "Zebra" |]
// Display the values of the array.
printfn "The original string array:"
printIndexAndValues stringArray
// Set the CurrentCulture to "en-US".
Thread.CurrentThread.CurrentCulture <- CultureInfo "en-US"
// Sort the values of the array.
Array.Sort stringArray
// Display the values of the array.
printfn "After sorting for the culture \"en-US\":"
printIndexAndValues stringArray
// Set the CurrentCulture to "da-DK".
Thread.CurrentThread.CurrentCulture <- CultureInfo "da-DK"
// Sort the values of the Array.
Array.Sort stringArray
// Display the values of the array.
printfn "After sorting for the culture \"da-DK\":"
printIndexAndValues stringArray
// The example displays the following output:
// The original string array:
// [0]: Apple
// [1]: Æble
// [2]: Zebra
//
// After sorting for the "en-US" culture:
// [0]: Æble
// [1]: Apple
// [2]: Zebra
//
// After sorting for the culture "da-DK":
// [0]: Apple
// [1]: Zebra
// [2]: Æble
Imports System.Globalization
Imports System.IO
Imports System.Threading
Public Class TextToFile
Public Shared Sub Main()
' Creates and initializes a new array to store
' these date/time objects.
Dim stringArray() As String = { "Apple", "Æble", "Zebra"}
' Displays the values of the array.
Console.WriteLine("The original string array:")
PrintIndexAndValues(stringArray)
' Set the CurrentCulture to "en-US".
Thread.CurrentThread.CurrentCulture = New CultureInfo("en-US")
' Sort the values of the Array.
Array.Sort(stringArray)
' Display the values of the array.
Console.WriteLine("After sorting for the ""en-US"" culture:")
PrintIndexAndValues(stringArray)
' Set the CurrentCulture to "da-DK".
Thread.CurrentThread.CurrentCulture = New CultureInfo("da-DK")
' Sort the values of the Array.
Array.Sort(stringArray)
' Displays the values of the Array.
Console.WriteLine("After sorting for the culture ""da-DK"":")
PrintIndexAndValues(stringArray)
End Sub
Public Shared Sub PrintIndexAndValues(myArray() As String)
For i As Integer = myArray.GetLowerBound(0) To myArray.GetUpperBound(0)
Console.WriteLine("[{0}]: {1}", i, myArray(i))
Next
Console.WriteLine()
End Sub
End Class
' The example displays the following output:
' The original string array:
' [0]: Apple
' [1]: Æble
' [2]: Zebra
'
' After sorting for the "en-US" culture:
' [0]: Æble
' [1]: Apple
' [2]: Zebra
'
' After sorting for the culture "da-DK":
' [0]: Apple
' [1]: Zebra
' [2]: Æble
Warning
문자열을 비교하는 주된 목적이 문자열이 같은지 여부를 확인하는 경우 메서드를 String.Equals 호출해야 합니다. 일반적으로 서수 비교를 수행하는 데 사용해야 Equals 합니다. 이 String.Compare 메서드는 주로 문자열을 정렬하기 위한 것입니다.
문자열 검색 메서드(예: String.StartsWith 및 String.IndexOf)는 문화권 구분 또는 서수 문자열 비교를 수행할 수도 있습니다. 다음 예제에서는 메서드를 사용하여 서수와 문화권 구분 비교의 차이점을 IndexOf 보여 줍니다. 현재 문화권이 영어(미국)인 문화권 구분 검색은 합자 "ø"와 일치하도록 부분 문자열 "oe"를 고려합니다. 소프트 하이픈(U+00AD)은 너비가 0인 문자이므로 검색은 소프트 하이픈을 동일한 String.Empty 것으로 처리하고 문자열의 시작 부분에서 일치 항목을 찾습니다. 반면 서수 검색은 두 경우 모두 일치 항목을 찾을 수 없습니다.
using System;
public class Example8
{
public static void Main()
{
// Search for "oe" and "œu" in "œufs" and "oeufs".
string s1 = "œufs";
string s2 = "oeufs";
FindInString(s1, "oe", StringComparison.CurrentCulture);
FindInString(s1, "oe", StringComparison.Ordinal);
FindInString(s2, "œu", StringComparison.CurrentCulture);
FindInString(s2, "œu", StringComparison.Ordinal);
Console.WriteLine();
string s3 = "co\u00ADoperative";
FindInString(s3, "\u00AD", StringComparison.CurrentCulture);
FindInString(s3, "\u00AD", StringComparison.Ordinal);
}
private static void FindInString(string s, string substring, StringComparison options)
{
int result = s.IndexOf(substring, options);
if (result != -1)
Console.WriteLine("'{0}' found in {1} at position {2}",
substring, s, result);
else
Console.WriteLine("'{0}' not found in {1}",
substring, s);
}
}
// The example displays the following output:
// 'oe' found in œufs at position 0
// 'oe' not found in œufs
// 'œu' found in oeufs at position 0
// 'œu' not found in oeufs
//
// '' found in cooperative at position 0
// '' found in cooperative at position 2
open System
let findInString (s: string) (substring: string) (options: StringComparison) =
let result = s.IndexOf(substring, options)
if result <> -1 then
printfn $"'{substring}' found in {s} at position {result}"
else
printfn $"'{substring}' not found in {s}"
// Search for "oe" and "œu" in "œufs" and "oeufs".
let s1 = "œufs"
let s2 = "oeufs"
findInString s1 "oe" StringComparison.CurrentCulture
findInString s1 "oe" StringComparison.Ordinal
findInString s2 "œu" StringComparison.CurrentCulture
findInString s2 "œu" StringComparison.Ordinal
printfn ""
let s3 = "co\u00ADoperative"
findInString s3 "\u00AD" StringComparison.CurrentCulture
findInString s3 "\u00AD" StringComparison.Ordinal
// The example displays the following output:
// 'oe' found in œufs at position 0
// 'oe' not found in œufs
// 'œu' found in oeufs at position 0
// 'œu' not found in oeufs
//
// '' found in cooperative at position 0
// '' found in cooperative at position 2
Module Example5
Public Sub Main()
' Search for "oe" and "œu" in "œufs" and "oeufs".
Dim s1 As String = "œufs"
Dim s2 As String = "oeufs"
FindInString(s1, "oe", StringComparison.CurrentCulture)
FindInString(s1, "oe", StringComparison.Ordinal)
FindInString(s2, "œu", StringComparison.CurrentCulture)
FindInString(s2, "œu", StringComparison.Ordinal)
Console.WriteLine()
Dim softHyphen As String = ChrW(&HAD)
Dim s3 As String = "co" + softHyphen + "operative"
FindInString(s3, softHyphen, StringComparison.CurrentCulture)
FindInString(s3, softHyphen, StringComparison.Ordinal)
End Sub
Private Sub FindInString(s As String, substring As String,
options As StringComparison)
Dim result As Integer = s.IndexOf(substring, options)
If result <> -1 Then
Console.WriteLine("'{0}' found in {1} at position {2}",
substring, s, result)
Else
Console.WriteLine("'{0}' not found in {1}",
substring, s)
End If
End Sub
End Module
' The example displays the following output:
' 'oe' found in œufs at position 0
' 'oe' not found in œufs
' 'œu' found in oeufs at position 0
' 'œu' not found in oeufs
'
' '' found in cooperative at position 0
' '' found in cooperative at position 2
문자열에서 검색
문자열 검색 메서드(예: String.StartsWith String.IndexOf및)는 문화권 구분 또는 서수 문자열 비교를 수행하여 지정된 문자열에서 문자 또는 부분 문자열을 찾을 수 있는지 여부를 확인할 수도 있습니다.
메서드와 같은 개별 문자 또는 메서드와 같은 IndexOf 문자 IndexOfAny 집합 중 하나를 검색하는 클래스의 검색 String 메서드는 모두 서수 검색을 수행합니다. 문자에 대한 문화권 구분 검색을 수행하려면 메서드(예: CompareInfo.IndexOf(String, Char) 또는 CompareInfo.LastIndexOf(String, Char))를 호출 CompareInfo 해야 합니다. 서수 및 문화권 구분 비교를 사용하여 문자를 검색한 결과는 매우 다를 수 있습니다. 예를 들어 합자 "Æ"(U+00C6)와 같은 미리 컴파일된 유니코드 문자를 검색하면 문화권에 따라 "AE"(U+041U+0045)와 같은 올바른 시퀀스에서 해당 구성 요소의 발생과 일치할 수 있습니다. 다음 예제에서는 개별 문자를 검색할 String.IndexOf(Char) 때와 CompareInfo.IndexOf(String, Char) 메서드의 차이점을 보여 줍니다. 합자 "æ"(U+00E6)는 en-US 문화권의 규칙을 사용하는 경우 문자열 "aerial"에서 찾을 수 있지만 da-DK 문화권의 규칙을 사용하거나 서수 비교를 수행할 때는 찾을 수 없습니다.
using System;
using System.Globalization;
public class Example17
{
public static void Main()
{
String[] cultureNames = { "da-DK", "en-US" };
CompareInfo ci;
String str = "aerial";
Char ch = 'æ'; // U+00E6
Console.Write("Ordinal comparison -- ");
Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
str.IndexOf(ch));
foreach (var cultureName in cultureNames) {
ci = CultureInfo.CreateSpecificCulture(cultureName).CompareInfo;
Console.Write("{0} cultural comparison -- ", cultureName);
Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
ci.IndexOf(str, ch));
}
}
}
// The example displays the following output:
// Ordinal comparison -- Position of 'æ' in aerial: -1
// da-DK cultural comparison -- Position of 'æ' in aerial: -1
// en-US cultural comparison -- Position of 'æ' in aerial: 0
open System.Globalization
let cultureNames = [| "da-DK"; "en-US" |]
let str = "aerial"
let ch = 'æ' // U+00E6
printf "Ordinal comparison -- "
printfn $"Position of '{ch}' in {str}: {str.IndexOf ch}"
for cultureName in cultureNames do
let ci = CultureInfo.CreateSpecificCulture(cultureName).CompareInfo
printf $"{cultureName} cultural comparison -- "
printfn $"Position of '{ch}' in {str}: {ci.IndexOf(str, ch)}"
// The example displays the following output:
// Ordinal comparison -- Position of 'æ' in aerial: -1
// da-DK cultural comparison -- Position of 'æ' in aerial: -1
// en-US cultural comparison -- Position of 'æ' in aerial: 0
Imports System.Globalization
Module Example19
Public Sub Main()
Dim cultureNames() As String = {"da-DK", "en-US"}
Dim ci As CompareInfo
Dim str As String = "aerial"
Dim ch As Char = "æ"c ' U+00E6
Console.Write("Ordinal comparison -- ")
Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
str.IndexOf(ch))
For Each cultureName In cultureNames
ci = CultureInfo.CreateSpecificCulture(cultureName).CompareInfo
Console.Write("{0} cultural comparison -- ", cultureName)
Console.WriteLine("Position of '{0}' in {1}: {2}", ch, str,
ci.IndexOf(str, ch))
Next
End Sub
End Module
' The example displays the following output:
' Ordinal comparison -- Position of 'æ' in aerial: -1
' da-DK cultural comparison -- Position of 'æ' in aerial: -1
' en-US cultural comparison -- Position of 'æ' in aerial: 0
반면, String 검색 옵션이 형식 StringComparison의 매개 변수로 명시적으로 지정되지 않은 경우 문자가 아닌 문자열을 검색하는 클래스 메서드는 문화권 구분 검색을 수행합니다. 유일한 예외는 Contains서수 검색을 수행하는 것입니다.
같음 테스트
이 메서드를 String.Compare 사용하여 정렬 순서에서 두 문자열의 관계를 확인합니다. 일반적으로 이 작업은 문화권에 민감한 작업입니다. 반면, 메서드를 String.Equals 호출하여 같음을 테스트합니다. 같음 테스트는 일반적으로 사용자 입력을 유효한 사용자 이름, 암호 또는 파일 시스템 경로와 같은 알려진 문자열과 비교하기 때문에 일반적으로 서수 작업입니다.
Warning
메서드를 호출 String.Compare 하고 반환 값이 0인지 여부를 확인하여 같음을 테스트할 수 있습니다. 그러나 이 방법은 권장되지 않습니다. 두 문자열이 같은지 여부를 확인하려면 메서드의 String.Equals 오버로드 중 하나를 호출해야 합니다. 두 메서드 모두 비교 형식을 명시적으로 지정하는 매개 변수를 포함 System.StringComparison 하므로 호출할 기본 오버로드는 인스턴스 Equals(String, StringComparison) 메서드 또는 정적 Equals(String, String, StringComparison) 메서드입니다.
다음 예제에서는 서수가 대신 사용해야 하는 경우 문화권에 민감한 비교를 수행하는 위험을 보여 줍니다. 이 경우 코드의 의도는 "FILE://" 또는 "file://"로 시작하는 URL에서 파일 시스템 액세스를 금지하기 위해 URL 시작 부분과 문자열 "FILE://"의 대/소문자를 구분하지 않는 비교를 수행합니다. 그러나 "file://"로 시작하는 URL에서 터키어(터키) 문화권을 사용하여 문화권 구분 비교를 수행하는 경우 소문자 "i"에 해당하는 터키어 대문자 값이 "I" 대신 "5"이므로 같음 비교가 실패합니다. 따라서 파일 시스템 액세스가 실수로 허용됩니다. 반면 서수 비교가 수행되면 같음 비교에 성공하고 파일 시스템 액세스가 거부됩니다.
using System;
using System.Globalization;
using System.Threading;
public class Example4
{
public static void Main()
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("tr-TR");
string filePath = "file://c:/notes.txt";
Console.WriteLine("Culture-sensitive test for equality:");
if (! TestForEquality(filePath, StringComparison.CurrentCultureIgnoreCase))
Console.WriteLine("Access to {0} is allowed.", filePath);
else
Console.WriteLine("Access to {0} is not allowed.", filePath);
Console.WriteLine("\nOrdinal test for equality:");
if (! TestForEquality(filePath, StringComparison.OrdinalIgnoreCase))
Console.WriteLine("Access to {0} is allowed.", filePath);
else
Console.WriteLine("Access to {0} is not allowed.", filePath);
}
private static bool TestForEquality(string str, StringComparison cmp)
{
int position = str.IndexOf("://");
if (position < 0) return false;
string substring = str.Substring(0, position);
return substring.Equals("FILE", cmp);
}
}
// The example displays the following output:
// Culture-sensitive test for equality:
// Access to file://c:/notes.txt is allowed.
//
// Ordinal test for equality:
// Access to file://c:/notes.txt is not allowed.
open System
open System.Globalization
open System.Threading
let testForEquality (str: string) (cmp: StringComparison) =
let position = str.IndexOf "://"
if position < 0 then false
else
let substring = str.Substring(0, position)
substring.Equals("FILE", cmp)
Thread.CurrentThread.CurrentCulture <- CultureInfo.CreateSpecificCulture "tr-TR"
let filePath = "file://c:/notes.txt"
printfn "Culture-sensitive test for equality:"
if not (testForEquality filePath StringComparison.CurrentCultureIgnoreCase) then
printfn $"Access to {filePath} is allowed."
else
printfn $"Access to {filePath} is not allowed."
printfn "\nOrdinal test for equality:"
if not (testForEquality filePath StringComparison.OrdinalIgnoreCase) then
printfn $"Access to {filePath} is allowed."
else
printfn $"Access to {filePath} is not allowed."
// The example displays the following output:
// Culture-sensitive test for equality:
// Access to file://c:/notes.txt is allowed.
//
// Ordinal test for equality:
// Access to file://c:/notes.txt is not allowed.
Imports System.Globalization
Imports System.Threading
Module Example7
Public Sub Main()
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("tr-TR")
Dim filePath As String = "file://c:/notes.txt"
Console.WriteLine("Culture-sensitive test for equality:")
If Not TestForEquality(filePath, StringComparison.CurrentCultureIgnoreCase) Then
Console.WriteLine("Access to {0} is allowed.", filePath)
Else
Console.WriteLine("Access to {0} is not allowed.", filePath)
End If
Console.WriteLine()
Console.WriteLine("Ordinal test for equality:")
If Not TestForEquality(filePath, StringComparison.OrdinalIgnoreCase) Then
Console.WriteLine("Access to {0} is allowed.", filePath)
Else
Console.WriteLine("Access to {0} is not allowed.", filePath)
End If
End Sub
Private Function TestForEquality(str As String, cmp As StringComparison) As Boolean
Dim position As Integer = str.IndexOf("://")
If position < 0 Then Return False
Dim substring As String = str.Substring(0, position)
Return substring.Equals("FILE", cmp)
End Function
End Module
' The example displays the following output:
' Culture-sensitive test for equality:
' Access to file://c:/notes.txt is allowed.
'
' Ordinal test for equality:
' Access to file://c:/notes.txt is not allowed.
표준화
일부 유니코드 문자에는 여러 표현이 있습니다. 예를 들어 다음 코드 포인트 중 어느 것이든 문자 "1"을 나타낼 수 있습니다.
- U+1EAF
- U+0103 U+0301
- U+0061 U+0306 U+0301
단일 문자에 대한 여러 표현은 검색, 정렬, 일치 및 기타 문자열 작업을 복잡하게 만듭니다.
유니코드 표준은 해당하는 이진 표현에 대해 유니코드 문자의 이진 표현 하나를 반환하는 정규화라는 프로세스를 정의합니다. 정규화는 다른 규칙을 따르는 정규화 양식이라는 여러 알고리즘을 사용할 수 있습니다. .NET은 유니코드 정규화 형식 C, D, KC 및 KD를 지원합니다. 문자열이 동일한 정규화 형식으로 정규화된 경우 서수 비교를 사용하여 비교할 수 있습니다.
서수 비교는 각 문자열에 있는 해당 Char 개체의 유니코드 스칼라 값에 대한 이진 비교입니다. 클래스에는 String 다음을 포함하여 서수 비교를 수행할 수 있는 여러 메서드가 포함됩니다.
매개 변수를 Compare포함하는 메서드, , StartsWithEquals, EndsWithIndexOf및 LastIndexOf 메서드의 모든 오버로드입니다StringComparison. 이 매개 변수의 값을 StringComparison.Ordinal OrdinalIgnoreCase 제공하는 경우 메서드는 서수 비교를 수행합니다.
메서드의 오버로드입니다 CompareOrdinal .
문자열 인스턴스의 Char 배열에서 값 또는 요소를 검색하는 Char 메서드입니다. 이러한 메서드에는 포함 IndexOf(Char) 및 Split(Char[]).
메서드를 호출 String.IsNormalized() 하여 문자열이 정규화 형식 C로 정규화되는지 여부를 확인하거나 메서드를 호출 String.IsNormalized(NormalizationForm) 하여 문자열이 지정된 정규화 형식으로 정규화되는지 여부를 확인할 수 있습니다. 메서드를 String.Normalize() 호출하여 문자열을 정규화 형식 C로 변환하거나 메서드를 String.Normalize(NormalizationForm) 호출하여 문자열을 지정된 정규화 양식으로 변환할 수도 있습니다. 문자열을 정규화하고 비교하는 방법에 대한 단계별 정보는 및 Normalize(NormalizationForm) 메서드를 Normalize() 참조하세요.
다음 간단한 예제에서는 문자열 정규화를 보여 줍니다. 세 가지 다른 문자열에서 세 가지 방법으로 문자 ""를 정의하고 같음의 서수 비교를 사용하여 각 문자열이 다른 두 문자열과 다른지 확인합니다. 그런 다음 각 문자열을 지원되는 정규화 형식으로 변환하고 지정된 정규화 형식으로 각 문자열의 서수 비교를 다시 수행합니다. 각 경우에서 두 번째 같음 테스트는 문자열이 같음을 보여 줍니다.
using System;
using System.Globalization;
using System.IO;
using System.Text;
public class Example13
{
private static StreamWriter sw;
public static void Main()
{
sw = new StreamWriter(@".\TestNorm1.txt");
// Define three versions of the same word.
string s1 = "sống"; // create word with U+1ED1
string s2 = "s\u00F4\u0301ng";
string s3 = "so\u0302\u0301ng";
TestForEquality(s1, s2, s3);
sw.WriteLine();
// Normalize and compare strings using each normalization form.
foreach (string formName in Enum.GetNames(typeof(NormalizationForm)))
{
sw.WriteLine("Normalization {0}:\n", formName);
NormalizationForm nf = (NormalizationForm) Enum.Parse(typeof(NormalizationForm), formName);
string[] sn = NormalizeStrings(nf, s1, s2, s3);
TestForEquality(sn);
sw.WriteLine("\n");
}
sw.Close();
}
private static void TestForEquality(params string[] words)
{
for (int ctr = 0; ctr <= words.Length - 2; ctr++)
for (int ctr2 = ctr + 1; ctr2 <= words.Length - 1; ctr2++)
sw.WriteLine("{0} ({1}) = {2} ({3}): {4}",
words[ctr], ShowBytes(words[ctr]),
words[ctr2], ShowBytes(words[ctr2]),
words[ctr].Equals(words[ctr2], StringComparison.Ordinal));
}
private static string ShowBytes(string str)
{
string result = null;
foreach (var ch in str)
result += $"{(ushort)ch:X4} ";
return result.Trim();
}
private static string[] NormalizeStrings(NormalizationForm nf, params string[] words)
{
for (int ctr = 0; ctr < words.Length; ctr++)
if (! words[ctr].IsNormalized(nf))
words[ctr] = words[ctr].Normalize(nf);
return words;
}
}
// The example displays the following output:
// sống (0073 1ED1 006E 0067) = sống (0073 00F4 0301 006E 0067): False
// sống (0073 1ED1 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
// sống (0073 00F4 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
//
// Normalization FormC:
//
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//
//
// Normalization FormD:
//
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//
//
// Normalization FormKC:
//
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//
//
// Normalization FormKD:
//
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
open System
open System.IO
open System.Text
do
use sw = new StreamWriter(@".\TestNorm1.txt")
let showBytes (str: string) =
let mutable result = ""
for ch in str do
result <- result + $"{uint16 ch:X4} "
result.Trim()
let testForEquality (words: string[]) =
for ctr = 0 to words.Length - 2 do
for ctr2 = ctr + 1 to words.Length - 1 do
sw.WriteLine("{0} ({1}) = {2} ({3}): {4}",
words[ctr], showBytes(words[ctr]),
words[ctr2], showBytes(words[ctr2]),
words[ctr].Equals(words[ctr2], StringComparison.Ordinal))
let normalizeStrings nf (words: string[]) =
for i = 0 to words.Length - 1 do
if not (words[i].IsNormalized nf) then
words[i] <- words[i].Normalize nf
words
// Define three versions of the same word.
let s1 = "sống" // create word with U+1ED1
let s2 = "s\u00F4\u0301ng"
let s3 = "so\u0302\u0301ng"
testForEquality [| s1; s2; s3 |]
sw.WriteLine()
// Normalize and compare strings using each normalization form.
for formName in Enum.GetNames typeof<NormalizationForm> do
sw.WriteLine("Normalization {0}:\n", formName)
let nf = Enum.Parse(typeof<NormalizationForm>, formName) :?> NormalizationForm
let sn = normalizeStrings nf [| s1; s2; s3|]
testForEquality sn
sw.WriteLine "\n"
// The example displays the following output:
// sống (0073 1ED1 006E 0067) = sống (0073 00F4 0301 006E 0067): False
// sống (0073 1ED1 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
// sống (0073 00F4 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
//
// Normalization FormC:
//
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//
//
// Normalization FormD:
//
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
//
//
// Normalization FormKC:
//
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
// sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
//
//
// Normalization FormKD:
//
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
// sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
Imports System.Globalization
Imports System.IO
Imports System.Text
Module Example16
Private sw As StreamWriter
Public Sub Main()
sw = New StreamWriter(".\TestNorm1.txt")
' Define three versions of the same word.
Dim s1 As String = "sống" ' create word with U+1ED1
Dim s2 As String = "s" + ChrW(&HF4) + ChrW(&H301) + "ng"
Dim s3 As String = "so" + ChrW(&H302) + ChrW(&H301) + "ng"
TestForEquality(s1, s2, s3)
sw.WriteLine()
' Normalize and compare strings using each normalization form.
For Each formName In [Enum].GetNames(GetType(NormalizationForm))
sw.WriteLine("Normalization {0}:", formName)
Dim nf As NormalizationForm = CType([Enum].Parse(GetType(NormalizationForm), formName),
NormalizationForm)
Dim sn() As String = NormalizeStrings(nf, s1, s2, s3)
TestForEquality(sn)
sw.WriteLine(vbCrLf)
Next
sw.Close()
End Sub
Private Sub TestForEquality(ParamArray words As String())
For ctr As Integer = 0 To words.Length - 2
For ctr2 As Integer = ctr + 1 To words.Length - 1
sw.WriteLine("{0} ({1}) = {2} ({3}): {4}",
words(ctr), ShowBytes(words(ctr)),
words(ctr2), ShowBytes(words(ctr2)),
words(ctr).Equals(words(ctr2), StringComparison.Ordinal))
Next
Next
End Sub
Private Function ShowBytes(str As String) As String
Dim result As String = Nothing
For Each ch In str
result += String.Format("{0} ", Convert.ToUInt16(ch).ToString("X4"))
Next
Return result.Trim()
End Function
Private Function NormalizeStrings(nf As NormalizationForm, ParamArray words() As String) As String()
For ctr As Integer = 0 To words.Length - 1
If Not words(ctr).IsNormalized(nf) Then
words(ctr) = words(ctr).Normalize(nf)
End If
Next
Return words
End Function
End Module
' The example displays the following output:
' sống (0073 1ED1 006E 0067) = sống (0073 00F4 0301 006E 0067): False
' sống (0073 1ED1 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
' sống (0073 00F4 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): False
'
' Normalization FormC:
'
' sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
' sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
' sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
'
'
' Normalization FormD:
'
' sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
' sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
' sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
'
'
' Normalization FormKC:
'
' sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
' sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
' sống (0073 1ED1 006E 0067) = sống (0073 1ED1 006E 0067): True
'
'
' Normalization FormKD:
'
' sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
' sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
' sống (0073 006F 0302 0301 006E 0067) = sống (0073 006F 0302 0301 006E 0067): True
정규화 및 정규화 양식에 대한 자세한 내용은 System.Text.NormalizationForm유니코드 표준 부록 #15: 유니코드 정규화 양식 및 unicode.org 웹 사이트의 정규화 FAQ를 참조하세요.
범주별 문자열 작업
클래스는 String 문자열 비교, 같음 문자열 테스트, 문자열에서 문자 또는 부분 문자열 찾기, 문자열 수정, 문자열에서 부분 문자열 추출, 문자열 결합, 값 서식 지정, 문자열 복사 및 문자열 정규화에 대한 멤버를 제공합니다.
문자열 비교
다음 String 메서드를 사용하여 문자열을 비교하여 정렬 순서에서 상대 위치를 확인할 수 있습니다.
Compare 는 정렬 순서에서 한 문자열과 두 번째 문자열의 관계를 나타내는 정수입니다.
CompareOrdinal 는 해당 코드 요소의 비교를 기반으로 한 문자열과 두 번째 문자열의 관계를 나타내는 정수입니다.
CompareTo 는 정렬 순서에서 현재 문자열 인스턴스와 두 번째 문자열의 관계를 나타내는 정수입니다. 메서드는 CompareTo(String) 클래스에 IComparable 대한 String 구현 및 IComparable<T> 기능을 제공합니다.
문자열이 같은지 테스트
메서드를 Equals 호출하여 두 문자열이 같은지 여부를 확인합니다. 인스턴스 Equals(String, String, StringComparison) 및 정적 Equals(String, StringComparison) 오버로드를 사용하면 비교가 문화권 구분 또는 서수인지 여부와 대/소문자를 고려하거나 무시할지 여부를 지정할 수 있습니다. 대부분의 같음 테스트는 서수이며, 시스템 리소스(예: 파일 시스템 개체)에 대한 액세스를 결정하는 같음 비교는 항상 서수여야 합니다.
문자열에서 문자 찾기
클래스에는 String 두 가지 종류의 검색 메서드가 포함됩니다.
특정 부분 문자열이 문자열 인스턴스에 있는지 여부를 나타내는 값을 반환 Boolean 하는 메서드입니다. 여기에는 , EndsWith및 메서드가 StartsWith 포함Contains됩니다.
문자열 인스턴스에서 부분 문자열의 시작 위치를 나타내는 메서드입니다. 여기에는 , IndexOfAny, LastIndexOf및 메서드가 LastIndexOfAny 포함IndexOf됩니다.
Warning
특정 부분 문자열이 아닌 특정 패턴에 대한 문자열을 검색하려면 정규식을 사용해야 합니다. 자세한 내용은 .NET 정규식을 참조 하세요.
문자열 수정
클래스에는 String 문자열 값을 수정하는 것처럼 보이는 다음 메서드가 포함됩니다.
PadLeft 는 문자열의 시작 부분에 지정된 문자를 하나 이상 삽입합니다.
PadRight 문자열의 끝에 지정된 문자가 하나 이상 삽입됩니다.
ToLower 문자열 ToLowerInvariant 의 모든 문자를 소문자로 변환합니다.
ToUpper 문자열 ToUpperInvariant 의 모든 문자를 대문자로 변환합니다.
Trim 는 문자열의 시작과 끝에서 문자의 모든 발생을 제거합니다.
TrimEnd 는 문자열의 끝에서 문자의 모든 발생을 제거합니다.
TrimStart 는 문자열의 시작 부분에서 문자의 모든 발생을 제거합니다.
Important
모든 문자열 수정 메서드는 새 String 개체를 반환합니다. 현재 인스턴스의 값은 수정하지 않습니다.
문자열에서 부분 문자열 추출
메서드는 String.Split 단일 문자열을 여러 문자열로 구분합니다. 메서드의 오버로드를 사용하면 여러 구분 기호를 지정하고, 메서드가 추출하는 부분 문자열 수를 제한하고, 부분 문자열에서 공백을 트리밍하고, 빈 문자열(구분 기호가 인접할 때 발생함)이 반환된 문자열에 포함되는지 여부를 지정할 수 있습니다.
문자열 결합
문자열 연결에는 다음 String 메서드를 사용할 수 있습니다.
값 서식 지정
이 메서드는 String.Format 복합 서식 지정 기능을 사용하여 문자열에 있는 하나 이상의 자리 표시자를 일부 개체 또는 값의 문자열 표현으로 대체합니다. 이 Format 메서드는 종종 다음을 수행하는 데 사용됩니다.
- 문자열에 숫자 값의 문자열 표현을 포함하려면
- 문자열에 날짜 및 시간 값의 문자열 표현을 포함하려면
- 문자열에 열거형 값의 문자열 표현을 포함하려면
- 문자열의 인터페이스를 지원하는 일부 개체의 문자열 표현을 IFormattable 포함하려면
- 더 큰 문자열 내의 필드에서 부분 문자열을 오른쪽 맞춤 또는 왼쪽 맞춤하려면
서식 지정 작업 및 예제에 대한 자세한 내용은 오버로드 요약을 Format 참조하세요.
문자열을 복사합니다.
다음 String 메서드를 호출하여 문자열의 복사본을 만들 수 있습니다.
문자열 정규화
유니코드에서 단일 문자에는 여러 코드 포인트가 있을 수 있습니다. 정규화는 이러한 해당 문자를 동일한 이진 표현으로 변환합니다. 메서드는 String.Normalize 정규화를 수행하고 메서드는 String.IsNormalized 문자열이 정규화되는지 여부를 결정합니다.
자세한 내용과 예제는 이 문서의 앞부분에 있는 정규화 섹션을 참조하세요.
.NET