다음을 통해 공유


System.Text.Rune 구조체

이 문서에서는 이 API에 대한 참조 설명서에 대한 추가 설명서를 제공합니다.

인스턴스는 Rune 서로게이트 범위를 제외한 모든 코드 지점(U+D800.)을 의미하는 유니코드 스칼라 값을 나타냅니다. U+DFFF). 형식의 생성자 및 변환 연산자는 입력의 유효성을 검사하므로 소비자는 기본 인스턴스가 잘 형성되어 있다고 가정하여 API를 Rune 호출할 수 있습니다.

유니코드 스칼라 값, 코드 포인트, 서로게이트 범위 및 잘 구성된 용어에 익숙하지 않은 경우 .NET의 문자 인코딩 소개를 참조하세요.

Rune 형식을 사용하는 경우

코드가 다음과 같은 경우 형식을 Rune 사용하는 것이 좋습니다.

  • 유니코드 스칼라 값이 필요한 API 호출
  • 서로게이트 쌍을 명시적으로 처리합니다.

유니코드 스칼라 값이 필요한 API

코드가 a 또는 a ReadOnlySpan<char>string 의 인스턴스를 반복 char 하는 경우 일부 char 메서드는 서로게이트 범위에 있는 인스턴스에서 char 제대로 작동하지 않습니다. 예를 들어 다음 API는 스칼라 값 char 이 올바르게 작동해야 합니다.

다음 예제에서는 인스턴스가 char 서로게이트 코드 포인트인 경우 제대로 작동하지 않는 코드를 보여 줍니다.

// THE FOLLOWING METHOD SHOWS INCORRECT CODE.
// DO NOT DO THIS IN A PRODUCTION APPLICATION.
int CountLettersBadExample(string s)
{
    int letterCount = 0;

    foreach (char ch in s)
    {
        if (char.IsLetter(ch))
        { letterCount++; }
    }

    return letterCount;
}
// THE FOLLOWING METHOD SHOWS INCORRECT CODE.
// DO NOT DO THIS IN A PRODUCTION APPLICATION.
let countLettersBadExample (s: string) =
    let mutable letterCount = 0

    for ch in s do
        if Char.IsLetter ch then
            letterCount <- letterCount + 1
    
    letterCount

다음은 다음과 같은 코드로 작동합니다.ReadOnlySpan<char>

// THE FOLLOWING METHOD SHOWS INCORRECT CODE.
// DO NOT DO THIS IN A PRODUCTION APPLICATION.
static int CountLettersBadExample(ReadOnlySpan<char> span)
{
    int letterCount = 0;

    foreach (char ch in span)
    {
        if (char.IsLetter(ch))
        { letterCount++; }
    }

    return letterCount;
}

앞의 코드는 영어와 같은 일부 언어에서 올바르게 작동합니다.

CountLettersInString("Hello")
// Returns 5

그러나 Osage와 같은 기본 다국어 평면 외부의 언어에서는 제대로 작동하지 않습니다.

CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 0

이 메서드가 Osage 텍스트에 대해 잘못된 결과를 반환하는 이유는 Osage 문자의 char 인스턴스가 서로게이트 코드 포인트이기 때문입니다. 단일 서로게이트 코드 지점에는 문자인지 여부를 확인하기에 충분한 정보가 없습니다.

대신 사용하도록 Rune 이 코드를 변경하는 경우 메서드는 기본 다국어 평면 외부의 char코드 포인트에서 올바르게 작동합니다.

int CountLetters(string s)
{
    int letterCount = 0;

    foreach (Rune rune in s.EnumerateRunes())
    {
        if (Rune.IsLetter(rune))
        { letterCount++; }
    }

    return letterCount;
}
let countLetters (s: string) =
    let mutable letterCount = 0

    for rune in s.EnumerateRunes() do
        if Rune.IsLetter rune then
            letterCount <- letterCount + 1

    letterCount

다음은 다음과 같은 코드로 작동합니다.ReadOnlySpan<char>

static int CountLetters(ReadOnlySpan<char> span)
{
    int letterCount = 0;

    foreach (Rune rune in span.EnumerateRunes())
    {
        if (Rune.IsLetter(rune))
        { letterCount++; }
    }

    return letterCount;
}

앞의 코드는 Osage 문자를 올바르게 계산합니다.

CountLettersInString("𐓏𐓘𐓻𐓘𐓻𐓟 𐒻𐓟")
// Returns 8

서로게이트 쌍을 명시적으로 처리하는 코드

코드가 Rune 서로게이트 코드 지점에서 명시적으로 작동하는 API를 호출하는 경우(예: 다음 메서드) 형식을 사용하는 것이 좋습니다.

예를 들어 다음 메서드에는 서로게이트 char 쌍을 처리하는 특수 논리가 있습니다.

static void ProcessStringUseChar(string s)
{
    Console.WriteLine("Using char");

    for (int i = 0; i < s.Length; i++)
    {
        if (!char.IsSurrogate(s[i]))
        {
            Console.WriteLine($"Code point: {(int)(s[i])}");
        }
        else if (i + 1 < s.Length && char.IsSurrogatePair(s[i], s[i + 1]))
        {
            int codePoint = char.ConvertToUtf32(s[i], s[i + 1]);
            Console.WriteLine($"Code point: {codePoint}");
            i++; // so that when the loop iterates it's actually +2
        }
        else
        {
            throw new Exception("String was not well-formed UTF-16.");
        }
    }
}

이러한 코드는 다음 예제와 같이 사용하는 Rune경우 더 간단합니다.

static void ProcessStringUseRune(string s)
{
    Console.WriteLine("Using Rune");

    for (int i = 0; i < s.Length;)
    {
        if (!Rune.TryGetRuneAt(s, i, out Rune rune))
        {
            throw new Exception("String was not well-formed UTF-16.");
        }

        Console.WriteLine($"Code point: {rune.Value}");
        i += rune.Utf16SequenceLength; // increment the iterator by the number of chars in this Rune
    }
}

Rune를 사용하지 않는 경우

코드인 경우 형식을 Rune 사용할 필요가 없습니다.

  • 정확한 char 일치 항목을 찾습니다.
  • 알려진 char 값에 문자열을 분할합니다.

코드를 사용하는 경우 형식을 Rune 사용하면 잘못된 결과가 반환됩니다.

  • 의 표시 문자 수를 계산합니다. string

정확한 char 일치 항목 찾기

다음 코드는 검색된 특정 문자를 반복 string 하여 첫 번째 일치 항목의 인덱스를 반환합니다. 코드가 단일 char문자로 표현되는 문자를 찾고 있으므로 이 코드를 사용하도록 Rune변경할 필요가 없습니다.

int GetIndexOfFirstAToZ(string s)
{
    for (int i = 0; i < s.Length; i++)
    {
        char thisChar = s[i];
        if ('A' <= thisChar && thisChar <= 'Z')
        {
            return i; // found a match
        }
    }

    return -1; // didn't find 'A' - 'Z' in the input string
}

알려진 문자열에서 문자열 분할 char

다음 예제와 같이 (공간) 또는 ',' (쉼표)와 같은 ' ' 구분 기호를 호출 string.Split 하고 사용하는 것이 일반적입니다.

string inputString = "🐂, 🐄, 🐆";
string[] splitOnSpace = inputString.Split(' ');
string[] splitOnComma = inputString.Split(',');

코드에서 단일 char문자로 표현되는 문자를 찾고 있으므로 여기서 사용할 Rune 필요가 없습니다.

의 표시 문자 수 계산 string

문자열의 Rune 인스턴스 수가 문자열을 표시할 때 표시되는 사용자 인식 가능 문자 수와 일치하지 않을 수 있습니다.

Rune 인스턴스는 유니코드 스칼라 값을 나타내므로 유니코드 텍스트 구분 지침을 따르는 구성 요소는 표시 문자를 계산하기 위한 구성 요소로 사용할 Rune 수 있습니다.

이 형식은 StringInfo 표시 문자 수를 계산하는 데 사용할 수 있지만 .NET 5 이상 이외의 .NET 구현에 대한 모든 시나리오에서 올바르게 계산되지는 않습니다.

자세한 내용은 Grapheme 클러스터를 참조 하세요.

를 인스턴스화하는 방법 Rune

인스턴스를 가져오는 방법에는 여러 가지가 있습니다 Rune . 생성자를 사용하여 다음에서 직접 만들 Rune 수 있습니다.

  • 코드 포인트입니다.

    Rune a = new Rune(0x0061); // LATIN SMALL LETTER A
    Rune b = new Rune(0x10421); // DESERET CAPITAL LETTER ER
    
  • 단일 char.

    Rune c = new Rune('a');
    
  • 서로게이트 char 쌍입니다.

    Rune d = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
    

입력이 유효한 유니코드 스칼라 값을 나타내지 않으면 모든 생성자가 throw ArgumentException 됩니다.

Rune.TryCreate 실패 시 예외를 throw하지 않으려는 호출자에 사용할 수 있는 메서드가 있습니다.

Rune 기존 입력 시퀀스에서 인스턴스를 읽을 수도 있습니다. 예를 들어 ReadOnlySpan<char> UTF-16 데이터를 나타내는 경우 메서드는 Rune.DecodeFromUtf16 입력 범위의 시작 부분에 첫 번째 Rune 인스턴스를 반환합니다. 메서드도 Rune.DecodeFromUtf8 마찬가지로 작동하여 ReadOnlySpan<byte> UTF-8 데이터를 나타내는 매개 변수를 허용합니다. 범위의 시작이 아니라 범위의 끝에서 읽는 것과 동일한 메서드가 있습니다.

의 쿼리 속성 Rune

인스턴스의 정수 코드 포인트 값을 Rune 얻으려면 속성을 사용합니다 Rune.Value .

Rune rune = new Rune('\ud83d', '\udd2e'); // U+1F52E CRYSTAL BALL
int codePoint = rune.Value; // = 128302 decimal (= 0x1F52E)

형식에서 사용할 수 있는 char 많은 정적 API도 형식에서 Rune 사용할 수 있습니다. 예를 들어, Rune.IsWhiteSpaceRune.GetUnicodeCategory 동일한 메서드와 Char.GetUnicodeCategory 같습니다Char.IsWhiteSpace. 메서드는 Rune 서로게이트 쌍을 올바르게 처리합니다.

다음 예제 코드는 입력으로 ReadOnlySpan<char> 사용하고 문자나 숫자가 아닌 모든 Rune 범위의 시작과 끝에서 트리밍합니다.

static ReadOnlySpan<char> TrimNonLettersAndNonDigits(ReadOnlySpan<char> span)
{
    // First, trim from the front.
    // If any Rune can't be decoded
    // (return value is anything other than "Done"),
    // or if the Rune is a letter or digit,
    // stop trimming from the front and
    // instead work from the end.
    while (Rune.DecodeFromUtf16(span, out Rune rune, out int charsConsumed) == OperationStatus.Done)
    {
        if (Rune.IsLetterOrDigit(rune))
        { break; }
        span = span[charsConsumed..];
    }

    // Next, trim from the end.
    // If any Rune can't be decoded,
    // or if the Rune is a letter or digit,
    // break from the loop, and we're finished.
    while (Rune.DecodeLastFromUtf16(span, out Rune rune, out int charsConsumed) == OperationStatus.Done)
    {
        if (Rune.IsLetterOrDigit(rune))
        { break; }
        span = span[..^charsConsumed];
    }

    return span;
}

API 간에는 몇 가지 API 차이점이 있습니다 charRune. 예시:

Rune UTF-8 또는 UTF-16으로 변환

유니 Rune 코드 스칼라 값이므로 UTF-8, UTF-16 또는 UTF-32 인코딩으로 변환할 수 있습니다. 이 Rune 형식은 UTF-8 및 UTF-16으로의 변환을 기본적으로 지원합니다.

Rune.EncodeToUtf16 인스턴스를 인스턴스로 Runechar 변환합니다. 인스턴스를 UTF-16으로 변환하여 Rune 발생하는 인스턴스 수를 char 쿼리하려면 이 속성을 사용합니다Rune.Utf16SequenceLength. UTF-8 변환에서도 비슷한 메서드가 있습니다.

다음 예제에서는 인스턴스를 Rune 배열로 char 변환합니다. 이 코드는 변수에 인스턴스가 Rune 있다고 가정합니다 rune .

char[] chars = new char[rune.Utf16SequenceLength];
int numCharsWritten = rune.EncodeToUtf16(chars);

A string 는 UTF-16 문자 시퀀스이므로 다음 예제에서는 인스턴스를 UTF-16으로 변환합니다 Rune .

string theString = rune.ToString();

다음 예제에서는 인스턴스를 Rune 바이트 배열로 UTF-8 변환합니다.

byte[] bytes = new byte[rune.Utf8SequenceLength];
int numBytesWritten = rune.EncodeToUtf8(bytes);

Rune.EncodeToUtf8 메서드는 Rune.EncodeToUtf16 작성된 실제 요소 수를 반환합니다. 대상 버퍼가 너무 짧아 결과를 포함할 수 없는 경우 예외를 throw합니다. 예외를 TryEncodeToUtf8TryEncodeToUtf16 방지하려는 호출자뿐만 아니라 throw되지 않는 메서드도 있습니다.

.NET 및 기타 언어로 실행

"rune"이라는 용어는 유니코드 표준에 정의되어 있지 않습니다. 이 용어는 UTF-8 생성으로 거슬러 올라갑니다. 롭 파이크와 켄 톰슨은 결국 코드 포인트로 알려질 것을 설명하는 용어를 찾고 있었다. 그들은 "rune"이라는 용어에 정착했고, Rob Pike는 나중에 Go 프로그래밍 언어에 대한 영향력을 통해 이 용어를 대중화하는 데 도움을 주었습니다.

그러나 .NET Rune 형식은 Go rune 형식과 동일하지 않습니다. Go rune 에서 형식은 . 에 대한 int32별칭입니다. Go rune은 유니코드 코드 포인트를 나타내기 위한 것이지만 서로게이트 코드 포인트 및 유효한 유니코드 코드 포인트가 아닌 값을 포함하여 32비트 값일 수 있습니다.

다른 프로그래밍 언어의 유사한 형식은 Rust의 기본 형식 또는 Swift의 Unicode.Scalar 형식을 참조하세요. 둘 다 유니코드 스칼라 값을 char 나타냅니다. 다음과 유사한 기능을 제공합니다. NET의 Rune 형식이며, 합법적인 유니코드 스칼라 값이 아닌 값의 인스턴스화를 허용하지 않습니다.