수색…
비고
.NET 문자열에서 System.String
은 System.Char
문자 시퀀스이며 각 문자는 UTF-16으로 인코딩 된 코드 단위입니다. 문자 와 .NET (및 많은 다른 언어)의 문자 언어 정의가 다르기 때문에 이러한 구분은 중요합니다.
grapheme 이라고 올바르게 명명되어야하는 한 문자 는 글리프 로 표시되며 하나 이상의 유니 코드 코드 포인트로 정의됩니다. 각 코드 포인트는 일련의 코드 단위 로 인코딩됩니다. 이제는 단일 System.Char
이 항상 문자를 나타내지 않는 이유를 분명히해야합니다. 현실 세계에서 어떻게 다른지 살펴 보겠습니다.
- 한 글자는 문자 결합으로 인해 두 개 이상의 코드 포인트가 생길 수 있습니다. à 두 개의 코드 포인트로 구성됩니다 : U + 0061 라틴 소문자 A 및 U + 0300 합계 그램 액센트 . 이것은
"à".Length == 2
이기 때문에 가장 일반적인 실수입니다.1
기대할 수 있습니다. - 위에서 설명한대로 예를 들어 A가 그라브 또는 두 개의 코드 포인트 단일 코드 포인트 U + 00E0 LATIN SMALL LETTER A를 할 수있다를 들어, 문자가 복제됩니다. 분명히
"\u00e0" == "\u0061\u0300"
("\u00e0".Length != "\u0061\u0300".Length
)와 같은 것을 비교해야합니다. 이는String.Normalize()
메서드로 문자열 정규화를 수행했기 때문에 가능합니다. - 유니 코드 시퀀스는 합성 또는 분해 된 시퀀스를 포함 할 수 있습니다. 예를 들어, 한 문자 U + D55C HAN CHARACTER 는 단일 코드 포인트 (UTF-16의 단일 코드 단위로 인코딩 됨) 또는 음절의 분해 된 시퀀스 ᄒ , be 및 ᆫ. 그들은 동등하게 비교되어야합니다.
- 하나의 코드 포인트는 하나 이상의 코드 단위로 인코딩 할 수있다 : 문자 𠂊 U + 2008A HAN 문자가 두로 인코딩됩니다
System.Char
("\ud840\udc8a"
UTF-16 : 그것은 단지 하나의 코드 포인트 인 경우에도) 인코딩은 고정 크기가 아닙니다! 예를 들어 응용 프로그램이 최대 길이를 적용하고 맹목적으로 문자열을 잘라내어 잘못된 문자열을 만들 수있는 경우 이는 수많은 버그 (심각한 보안 버그)의 원인입니다. - 일부 언어가 소리를 나타내는 두 글자 체코 채널에서 시간 후 독립 편지 (예를과 trigraph를, 그리고 내가 문자열 목록을 주문 후시 전에 케미 전에 fyzika있을 것이다.
텍스트 처리에 관한 더 많은 문제가 있습니다 ( 예를 들어 문자 비교를 통해 유니 코드 인식 문자 를 어떻게 수행 할 수 있습니까?). 광범위한 소개와 관련 인수에 대한 링크가 더 많습니다.
일반적으로 국제 텍스트를 다룰 때이 간단한 함수를 사용하여 문자열의 텍스트 요소를 열거 할 수 있습니다 (유니 코드 사로 게이트 및 인코딩을 중단하지 않아야 함).
public static class StringExtensions
{
public static IEnumerable<string> EnumerateCharacters(this string s)
{
if (s == null)
return Enumerable.Empty<string>();
var enumerator = StringInfo.GetTextElementEnumerator(s.Normalize());
while (enumerator.MoveNext())
yield return (string)enumerator.Value;
}
}
고유 문자 수 계산
Remarks 섹션에서 설명한 이유 때문에 별개의 문자를 계산해야하는 경우 Length
가 아닌 System.Char
배열의 길이가 Unicode 코드 포인트가 아닌 코드 단위가되기 때문에 단순히 Length
속성을 사용할 수 없습니다 도 아니다 graphemes). 예를 들어, 단순히 text.Distinct().Count()
를 text.Distinct().Count()
올바르지 않은 결과를 얻고 코드를 수정합니다.
int distinctCharactersCount = text.EnumerateCharacters().Count();
한 단계 더 나아가 각 문자의 발생 횟수 를 계산 하는 것입니다. 성능이 문제가되지 않는다면 다음과 같이 간단하게 처리 할 수 있습니다 (이 경우 대소 문자는 관계 없음).
var frequencies = text.EnumerateCharacters()
.GroupBy(x => x, StringComparer.CurrentCultureIgnoreCase)
.Select(x => new { Character = x.Key, Count = x.Count() };
글자 수
문자 수를 계산해야하는 경우 설명 섹션에서 설명한 이유 때문에 문자가 아닌 코드 단위 (유니 코드 코드 포인트가 아닌 System.Char
배열의 길이이기 때문에 Length 속성을 사용할 수 없습니다. graphemes). 올바른 코드는 다음과 같습니다.
int length = text.EnumerateCharacters().Count();
작은 최적화는이 목적을 위해 특별히 EnumerateCharacters()
확장 메서드를 다시 작성할 수 있습니다.
public static class StringExtensions
{
public static int CountCharacters(this string text)
{
if (String.IsNullOrEmpty(text))
return 0;
int count = 0;
var enumerator = StringInfo.GetTextElementEnumerator(text);
while (enumerator.MoveNext())
++count;
return count;
}
}
문자의 발생 수 계산
설명 섹션에 설명 된 이유 때문에 특정 코드 단위의 발생을 계산하지 않는 한 간단히이 작업을 수행 할 수 없습니다.
int count = text.Count(x => x == ch);
보다 복잡한 기능이 필요합니다.
public static int CountOccurrencesOf(this string text, string character)
{
return text.EnumerateCharacters()
.Count(x => String.Equals(x, character, StringComparer.CurrentCulture));
}
문자열 비교 (문화 비교가 아닌 문자 비교와 달리)는 항상 특정 문화권에 대한 규칙에 따라 수행되어야합니다.
고정 길이 블록으로 문자열 분할
우리는 문자열을 임의의 점으로 나눌 수 없습니다. 왜냐하면 System.Char
가 결합 문자 또는 대리 문자의 일부이기 때문에 System.Char
가 단독으로 유효하지 않을 수 있기 때문입니다. 그런 다음 코드는이를 고려해야합니다. ( 길이가 내가 아닌 수식 의 수를 의미합니다. 코드 단위 수 ) :
public static IEnumerable<string> Split(this string value, int desiredLength)
{
var characters = StringInfo.GetTextElementEnumerator(value);
while (characters.MoveNext())
yield return String.Concat(Take(characters, desiredLength));
}
private static IEnumerable<string> Take(TextElementEnumerator enumerator, int count)
{
for (int i = 0; i < count; ++i)
{
yield return (string)enumerator.Current;
if (!enumerator.MoveNext())
yield break;
}
}
문자열을 다른 인코딩으로 변환
.NET 문자열에는 System.Char
(UTF-16 코드 단위)이 포함됩니다. 다른 인코딩으로 텍스트를 저장 (또는 관리)하려면 System.Byte
배열로 작업해야합니다.
변환은 System.Text.Encoder
및 System.Text.Decoder
에서 파생 된 클래스에 의해 수행됩니다. System.Text.Encoder
는 다른 인코딩 (바이트 X 인코딩 된 배열 byte[]
에서 UTF-16으로 인코딩 된 System.String
및 vice -versa).
인코더 / 디코더는 일반적으로 서로 아주 가까이서 작동하기 때문에 System.Text.Encoding
에서 파생 된 클래스로 함께 그룹화되므로 파생 클래스는 일반적인 인코딩 (UTF-8, UTF-16 등)과의 변환을 제공합니다.
예 :
문자열을 UTF-8로 변환하십시오.
byte[] data = Encoding.UTF8.GetBytes("This is my text");
UTF-8 데이터를 문자열로 변환
var text = Encoding.UTF8.GetString(data);
기존 텍스트 파일의 인코딩 변경
이 코드는 UTF-8로 인코딩 된 텍스트 파일의 내용을 읽어 UTF-16으로 다시 인코딩하여 저장합니다. 파일이 크면 모든 내용을 메모리로 읽어 들일 것이므로이 코드는 최적이 아닙니다.
var content = File.ReadAllText(path, Encoding.UTF8);
File.WriteAllText(content, Encoding.UTF16);
Object.ToString () 가상 메소드
.NET의 모든 것은 객체이므로 모든 유형에는 Object
클래스에 정의 된 ToString()
메서드 가 있습니다.이 메서드는 재정의 될 수 있습니다. 이 메소드의 디폴트의 구현은, 단지 형태의 이름을 돌려줍니다.
public class Foo
{
}
var foo = new Foo();
Console.WriteLine(foo); // outputs Foo
ToString()
은 값을 문자열과 concatinating 할 때 암시 적으로 호출됩니다.
public class Foo
{
public override string ToString()
{
return "I am Foo";
}
}
var foo = new Foo();
Console.WriteLine("I am bar and "+foo);// outputs I am bar and I am Foo
이 방법의 결과는 디버깅 도구에서도 광범위하게 사용됩니다. 어떤 이유로이 메서드를 재정의하고 싶지 않고 디버거가 사용자의 유형 값을 표시하는 방법을 사용자 정의하려면 DebuggerDisplay Attribute ( MSDN )를 사용하십시오.
// [DebuggerDisplay("Person = FN {FirstName}, LN {LastName}")]
[DebuggerDisplay("Person = FN {"+nameof(Person.FirstName)+"}, LN {"+nameof(Person.LastName)+"}")]
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set;}
// ...
}
문자열의 불변성
문자열은 변경할 수 없습니다. 기존 문자열을 변경할 수 없습니다. 문자열에 대한 모든 연산은 새 값을 갖는 문자열의 새 인스턴스를 만듭니다. 아주 긴 문자열에서 단일 문자를 대체해야하는 경우 새 값으로 메모리가 할당된다는 의미입니다.
string veryLongString = ...
// memory is allocated
string newString = veryLongString.Remove(0,1); // removes first character of the string.
문자열 값으로 여러 작업을 수행해야하는 경우 효율적인 문자열 조작을 위해 설계된 StringBuilder
클래스 를 사용하십시오.
var sb = new StringBuilder(someInitialString);
foreach(var str in manyManyStrings)
{
sb.Append(str);
}
var finalString = sb.ToString();
Сomparing strings
String
에도 불구하고 참조 유형 ==
연산자는 참조가 아닌 문자열 값을 비교합니다.
아시다시피 string
은 문자 배열입니다. 그러나 문자열의 평등성 검사와 비교가 문자 단위로 수행된다고 생각하면 틀린 것입니다. 이 작업은 문화권에 따라 다릅니다 (아래 비고 참조). 일부 문자 시퀀스는 문화 에 따라 동일하게 처리 될 수 있습니다.
두 문자열의 Length
속성 을 비교하여 단락 평등 검사를하기 전에 두 번 생각하십시오!
기본 동작을 변경해야하는 경우 추가 StringComparison
열거 형 값을 허용하는 String.Equals
메서드의 오버로드를 사용하십시오.