문자열을 비교하여 "이 두 문자열이 같은가요?" 또는 "정렬할 때 이러한 문자열을 어떤 순서로 배치해야 하나요?"라는 두 가지 질문 중 하나에 대답합니다.
다음 요소는 이 두 가지 질문을 복잡하게 만듭니다.
- 서수(순서) 비교 또는 언어(문법) 비교를 선택할 수 있습니다.
- 케이스가 중요한지 선택할 수 있습니다.
- 문화권별 비교를 선택할 수 있습니다.
- 언어 비교는 문화권과 플랫폼에 따라 다릅니다.
System.StringComparison 열거형 필드는 다음 선택 항목을 나타냅니다.
- CurrentCulture: 문화권 구분 정렬 규칙과 현재 문화권을 사용하여 문자열을 비교합니다.
- CurrentCultureIgnoreCase: 문화권 구분 정렬 규칙, 현재 문화권을 사용하여 문자열을 비교하고 비교되는 문자열의 경우를 무시합니다.
- InvariantCulture: 문화에 민감한 정렬 규칙과 고정된 문화권을 사용하여 문자열을 비교합니다.
- InvariantCultureIgnoreCase: 문화권 구분 정렬 규칙, 고정 문화권을 사용하여 문자열을 비교하고 비교되는 문자열의 경우를 무시합니다.
- 서수: 문자열을 서수(바이너리) 정렬 규칙으로 비교합니다.
- OrdinalIgnoreCase: 서수(이진) 정렬 규칙을 사용하여 문자열을 비교하고 비교되는 문자열의 경우를 무시합니다.
문자열을 비교할 때 순서를 정의합니다. 비교는 문자열 시퀀스를 정렬하는 데 사용됩니다. 시퀀스가 알려진 순서대로 되면 소프트웨어와 사람 모두 검색하기가 더 쉽습니다. 다른 비교에서는 문자열이 동일한지 확인할 수 있습니다. 이러한 동일성 검사는 같음과 유사하지만 대/소문자 차이와 같은 일부 차이점은 무시될 수 있습니다.
기본 서수 비교
기본적으로 가장 일반적인 작업은 다음과 같습니다.
- String.Equals
-
String.Equality 및 String.Inequality, 즉, 동등 연산자
==와!=는 각각 대/소문자 구분을 통해 서수 비교를 수행합니다. String.Equals 에는 정렬 규칙을 변경하기 위해 인수를 제공할 수 있는 StringComparison 오버로드가 있습니다. 다음은 해당 예입니다.
string root = @"C:\users";
string root2 = @"C:\Users";
bool result = root.Equals(root2);
Console.WriteLine($"Ordinal comparison: <{root}> and <{root2}> are {(result ? "equal." : "not equal.")}");
result = root.Equals(root2, StringComparison.Ordinal);
Console.WriteLine($"Ordinal comparison: <{root}> and <{root2}> are {(result ? "equal." : "not equal.")}");
Console.WriteLine($"Using == says that <{root}> and <{root2}> are {(root == root2 ? "equal" : "not equal")}");
기본 서수 비교는 문자열을 비교할 때 언어 규칙을 고려하지 않습니다. 두 문자열에서 각 Char 개체의 이진 값을 비교합니다. 따라서 기본 서수 비교도 대/소문자를 구분합니다.
등호 테스트 String.Equals 및 연산자 == 및 !=는 문자열 비교에서 String.CompareTo 및 Compare(String, String) 메서드를 사용하는 것과 다릅니다. 모두 대/소문자를 구분하는 비교를 수행합니다. 그러나 동등성 테스트는 서수 비교를 수행하는 반면, CompareTo 및 Compare 메서드는 현재의 문화권에 맞춘 문화적 언어 비교를 수행합니다. 수행할 비교 유형을 명시적으로 지정하는 오버로드를 호출하여 코드의 의도를 명확하게 합니다.
is 연산자와 상수 패턴은 오른쪽 피연산자가 상수인 경우 == 대신 사용할 수 있습니다.
대/소문자를 구분하지 않는 서수 비교
이 String.Equals(String, StringComparison) 메서드를 사용하면 대소문자를 구분하지 않는 서수 비교를 위한 StringComparison 값을 StringComparison.OrdinalIgnoreCase으로 지정할 수 있습니다. 인수의 값을 String.Compare(String, String, StringComparison)StringComparison.OrdinalIgnoreCase 지정하는 경우 대/소문자를 구분하지 않는 서수 비교를 수행하는 정적 StringComparison 메서드도 있습니다. 이러한 비교는 다음 코드에 나와 있습니다.
string root = @"C:\users";
string root2 = @"C:\Users";
bool result = root.Equals(root2, StringComparison.OrdinalIgnoreCase);
bool areEqual = String.Equals(root, root2, StringComparison.OrdinalIgnoreCase);
int comparison = String.Compare(root, root2, comparisonType: StringComparison.OrdinalIgnoreCase);
Console.WriteLine($"Ordinal ignore case: <{root}> and <{root2}> are {(result ? "equal." : "not equal.")}");
Console.WriteLine($"Ordinal static ignore case: <{root}> and <{root2}> are {(areEqual ? "equal." : "not equal.")}");
if (comparison < 0)
{
Console.WriteLine($"<{root}> is less than <{root2}>");
}
else if (comparison > 0)
{
Console.WriteLine($"<{root}> is greater than <{root2}>");
}
else
{
Console.WriteLine($"<{root}> and <{root2}> are equivalent in order");
}
이러한 메서드는 불변 문화권의 대/소문자 구분 규칙을 사용하여 대/소문자를 구분하지 않는 서수 비교를 수행합니다.
언어 비교
많은 문자열 비교 메서드(예: String.StartsWith)는 기본적으로 현재 문화 권에 대한 언어 규칙을 사용하여 입력 순서를 지정합니다. 이 언어 비교를 "단어 정렬 순서"라고도 합니다. 언어 비교를 수행할 때 일부 무수 유니코드 문자에는 특수 가중치가 할당될 수 있습니다. 예를 들어 하이픈 "-"에는 작은 가중치가 할당되어 "co-op" 및 "coop"이 정렬 순서대로 나란히 나타날 수 있습니다. 일부 인쇄되지 않는 컨트롤 문자는 무시될 수 있습니다. 또한 일부 유니코드 문자는 Char 인스턴스의 시퀀스와 동등할 수 있습니다. 다음 예제에서는 "거리에서 춤을 춘다"라는 문구를 독일어로 사용하고 한 문자열에 "ss"(U+0073 U+0073)를 사용하고 다른 문자열에는 'ß'(U+00DF)를 사용합니다. 언어적으로(Windows에서) "ss"는 "en-US" 및 "de-DE" 문화권 모두에서 독일어 Esszet: 'ß' 문자와 같습니다.
string first = "Sie tanzen auf der Straße.";
string second = "Sie tanzen auf der Strasse.";
Console.WriteLine($"First sentence is <{first}>");
Console.WriteLine($"Second sentence is <{second}>");
bool equal = String.Equals(first, second, StringComparison.InvariantCulture);
Console.WriteLine($"The two strings {(equal == true ? "are" : "are not")} equal.");
showComparison(first, second);
string word = "coop";
string words = "co-op";
string other = "cop";
showComparison(word, words);
showComparison(word, other);
showComparison(words, other);
void showComparison(string one, string two)
{
int compareLinguistic = String.Compare(one, two, StringComparison.InvariantCulture);
int compareOrdinal = String.Compare(one, two, StringComparison.Ordinal);
if (compareLinguistic < 0)
{
Console.WriteLine($"<{one}> is less than <{two}> using invariant culture");
}
else if (compareLinguistic > 0)
{
Console.WriteLine($"<{one}> is greater than <{two}> using invariant culture");
}
else
{
Console.WriteLine($"<{one}> and <{two}> are equivalent in order using invariant culture");
}
if (compareOrdinal < 0)
{
Console.WriteLine($"<{one}> is less than <{two}> using ordinal comparison");
}
else if (compareOrdinal > 0)
{
Console.WriteLine($"<{one}> is greater than <{two}> using ordinal comparison");
}
else
{
Console.WriteLine($"<{one}> and <{two}> are equivalent in order using ordinal comparison");
}
}
Windows에서 .NET 5 이전에는 언어 비교에서 서수 비교로 변경하면 "cop", "coop" 및 "co-op"의 정렬 순서가 변경됩니다. 또한 두 독일어 문장은 서로 다른 비교 유형을 사용하여 다르게 비교됩니다. .NET 5 이전에는 .NET 세계화 API에서 NLS(국가 언어 지원) 라이브러리를 사용했습니다. .NET 5 및 이후 버전에서는 .NET 세계화 API가 국제 컴포넌트 ICU(International Components for Unicode) 라이브러리를 사용하여, 지원되는 모든 운영 체제에서 .NET의 세계화 동작을 통일합니다.
특정 문화권을 사용한 비교
다음 예제에서는 en-US 및 de-DE 문화권의 CultureInfo 개체를 저장합니다. 비교는 문화권별 비교를 CultureInfo 보장하기 위해 개체를 사용하여 수행됩니다. 사용되는 문화권은 언어 비교에 영향을 줍니다. 다음 예제에서는 "en-US" 문화권 및 "de-DE" 문화권을 사용하여 두 독일어 문장을 비교한 결과를 보여 줍니다.
string first = "Sie tanzen auf der Straße.";
string second = "Sie tanzen auf der Strasse.";
Console.WriteLine($"First sentence is <{first}>");
Console.WriteLine($"Second sentence is <{second}>");
var en = new System.Globalization.CultureInfo("en-US");
// For culture-sensitive comparisons, use the String.Compare
// overload that takes a StringComparison value.
int i = String.Compare(first, second, en, System.Globalization.CompareOptions.None);
Console.WriteLine($"Comparing in {en.Name} returns {i}.");
var de = new System.Globalization.CultureInfo("de-DE");
i = String.Compare(first, second, de, System.Globalization.CompareOptions.None);
Console.WriteLine($"Comparing in {de.Name} returns {i}.");
bool b = String.Equals(first, second, StringComparison.CurrentCulture);
Console.WriteLine($"The two strings {(b ? "are" : "are not")} equal.");
string word = "coop";
string words = "co-op";
string other = "cop";
showComparison(word, words, en);
showComparison(word, other, en);
showComparison(words, other, en);
void showComparison(string one, string two, System.Globalization.CultureInfo culture)
{
int compareLinguistic = String.Compare(one, two, en, System.Globalization.CompareOptions.None);
int compareOrdinal = String.Compare(one, two, StringComparison.Ordinal);
if (compareLinguistic < 0)
{
Console.WriteLine($"<{one}> is less than <{two}> using en-US culture");
}
else if (compareLinguistic > 0)
{
Console.WriteLine($"<{one}> is greater than <{two}> using en-US culture");
}
else
{
Console.WriteLine($"<{one}> and <{two}> are equivalent in order using en-US culture");
}
if (compareOrdinal < 0)
{
Console.WriteLine($"<{one}> is less than <{two}> using ordinal comparison");
}
else if (compareOrdinal > 0)
{
Console.WriteLine($"<{one}> is greater than <{two}> using ordinal comparison");
}
else
{
Console.WriteLine($"<{one}> and <{two}> are equivalent in order using ordinal comparison");
}
}
문화에 민감한 비교는 일반적으로 사용자가 입력한 문자열을 다른 사용자가 입력한 문자열과 비교하고 정렬하는 데 사용됩니다. 이러한 문자열의 문자 및 정렬 규칙은 사용자 컴퓨터의 로캘에 따라 달라질 수 있습니다. 동일한 문자를 포함하는 문자열도 현재 스레드의 문화권에 따라 다르게 정렬될 수 있습니다.
배열에 있는 문자열의 언어적 정렬 및 검색
다음 예제에서는 현재 문화권에 종속된 언어 비교를 사용하여 배열에서 문자열을 정렬하고 검색하는 방법을 보여 줍니다. System.StringComparer 매개변수를 사용하는 Array 정적 메서드를 사용합니다.
다음 예제에서는 현재 문화권을 사용하여 문자열 배열을 정렬하는 방법을 보여 줍니다.
string[] lines =
[
@"c:\public\textfile.txt",
@"c:\public\textFile.TXT",
@"c:\public\Text.txt",
@"c:\public\testfile2.txt"
];
Console.WriteLine("Non-sorted order:");
foreach (string s in lines)
{
Console.WriteLine($" {s}");
}
Console.WriteLine("\n\rSorted order:");
// Specify Ordinal to demonstrate the different behavior.
Array.Sort(lines, StringComparer.CurrentCulture);
foreach (string s in lines)
{
Console.WriteLine($" {s}");
}
배열이 정렬되면 이진 검색을 사용하여 항목을 검색할 수 있습니다. 컬렉션 중간에 이진 검색이 시작되어 컬렉션의 절반이 검색된 문자열을 포함할지 확인합니다. 이후의 각 비교에서는 컬렉션의 나머지 부분을 절반으로 세분화합니다. 배열은 .를 사용하여 정렬됩니다 StringComparer.CurrentCulture. 로컬 함수 ShowWhere 는 문자열이 발견된 위치에 대한 정보를 표시합니다. 문자열을 찾을 수 없는 경우 반환된 값은 문자열이 발견된 경우의 위치를 나타냅니다.
string[] lines =
[
@"c:\public\textfile.txt",
@"c:\public\textFile.TXT",
@"c:\public\Text.txt",
@"c:\public\testfile2.txt"
];
Array.Sort(lines, StringComparer.CurrentCulture);
string searchString = @"c:\public\TEXTFILE.TXT";
Console.WriteLine($"Binary search for <{searchString}>");
int result = Array.BinarySearch(lines, searchString, StringComparer.CurrentCulture);
ShowWhere<string>(lines, result);
Console.WriteLine($"{(result > 0 ? "Found" : "Did not find")} {searchString}");
void ShowWhere<T>(T[] array, int index)
{
if (index < 0)
{
index = ~index;
Console.Write("Not found. Sorts between: ");
if (index == 0)
{
Console.Write("beginning of sequence and ");
}
else
{
Console.Write($"{array[index - 1]} and ");
}
if (index == array.Length)
{
Console.WriteLine("end of sequence.");
}
else
{
Console.WriteLine($"{array[index]}.");
}
}
else
{
Console.WriteLine($"Found at index {index}.");
}
}
컬렉션에서 순서 기반 정렬 및 검색
다음 코드는 컬렉션 클래스를 System.Collections.Generic.List<T> 사용하여 문자열을 저장합니다. 문자열은 메서드를 사용하여 정렬됩니다 List<T>.Sort . 이 메서드에는 두 문자열을 비교하고 정렬하는 대리자가 필요합니다. 이 메서드는 String.CompareTo 해당 비교 함수를 제공합니다. 샘플을 실행하고 순서를 관찰합니다. 이 정렬 작업은 서수 방식으로 대/소문자를 구분하여 정렬을 수행합니다. 정적 String.Compare 메서드를 사용하여 다른 비교 규칙을 지정합니다.
List<string> lines =
[
@"c:\public\textfile.txt",
@"c:\public\textFile.TXT",
@"c:\public\Text.txt",
@"c:\public\testfile2.txt"
];
Console.WriteLine("Non-sorted order:");
foreach (string s in lines)
{
Console.WriteLine($" {s}");
}
Console.WriteLine("\n\rSorted order:");
lines.Sort((left, right) => left.CompareTo(right));
foreach (string s in lines)
{
Console.WriteLine($" {s}");
}
정렬되면 이진 검색을 사용하여 문자열 목록을 검색할 수 있습니다. 다음 샘플에서는 동일한 비교 함수를 사용하여 정렬된 목록을 검색하는 방법을 보여줍니다. 로컬 함수 ShowWhere는 찾고 있는 텍스트의 위치나 예상 위치를 보여줍니다.
List<string> lines =
[
@"c:\public\textfile.txt",
@"c:\public\textFile.TXT",
@"c:\public\Text.txt",
@"c:\public\testfile2.txt"
];
lines.Sort((left, right) => left.CompareTo(right));
string searchString = @"c:\public\TEXTFILE.TXT";
Console.WriteLine($"Binary search for <{searchString}>");
int result = lines.BinarySearch(searchString);
ShowWhere<string>(lines, result);
Console.WriteLine($"{(result > 0 ? "Found" : "Did not find")} {searchString}");
void ShowWhere<T>(IList<T> collection, int index)
{
if (index < 0)
{
index = ~index;
Console.Write("Not found. Sorts between: ");
if (index == 0)
{
Console.Write("beginning of sequence and ");
}
else
{
Console.Write($"{collection[index - 1]} and ");
}
if (index == collection.Count)
{
Console.WriteLine("end of sequence.");
}
else
{
Console.WriteLine($"{collection[index]}.");
}
}
else
{
Console.WriteLine($"Found at index {index}.");
}
}
항상 정렬 및 검색에 동일한 유형의 비교를 사용해야 합니다. 정렬 및 검색에 다른 비교 형식을 사용하면 예기치 않은 결과가 생성됩니다.
컬렉션 클래스 System.Collections.Hashtable, System.Collections.Generic.Dictionary<TKey,TValue>, 및 System.Collections.Generic.List<T>에는 요소 또는 키의 형식이 string일 때 System.StringComparer 매개 변수를 사용하는 생성자가 있습니다. 일반적으로 가능하면 이러한 생성자를 사용하고 둘 중 하나 StringComparer.Ordinal 또는 StringComparer.OrdinalIgnoreCase를 지정해야 합니다.
참고하십시오
.NET