수색…


비고

.NET 문자열에서 System.StringSystem.Char 문자 시퀀스이며 각 문자는 UTF-16으로 인코딩 된 코드 단위입니다. 문자 와 .NET (및 많은 다른 언어)의 문자 언어 정의가 다르기 때문에 이러한 구분은 중요합니다.

grapheme 이라고 올바르게 명명되어야하는 한 문자글리프 로 표시되며 하나 이상의 유니 코드 코드 포인트로 정의됩니다. 각 코드 포인트는 일련의 코드 단위 로 인코딩됩니다. 이제는 단일 System.Char 이 항상 문자를 나타내지 않는 이유를 분명히해야합니다. 현실 세계에서 어떻게 다른지 살펴 보겠습니다.

  • 한 글자는 문자 결합으로 인해 두 개 이상의 코드 포인트가 생길 수 있습니다. à 두 개의 코드 포인트로 구성됩니다 : U + 0061 라틴 소문자 AU + 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.EncoderSystem.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 메서드의 오버로드를 사용하십시오.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow