2017-01-17 4 views
-3

그래서 스크립팅 언어를 작성 중이며 편리한 목표 중 하나는 문자열 작업입니다. 나는 C++에서 몇 가지 아이디어를 시도했다.C++ 유니 코드 : 바이트, 코드 포인트 및 Graphem

  • 문자열은 코드 포인트 색인을 포함하는 벡터를 반환하는 바이트 및 자유 함수 시퀀스입니다.
  • 문자열과 인덱스가 포함 된 벡터를 결합하는 래퍼 클래스입니다.

두 아이디어 모두에 문제가 있으며 그 문제는 내가 무엇을 반환해야하는지입니다. char가 될 수는 없으며, 문자열이라면 공간이 낭비 될 것입니다.

정확하게 4 바이트의 문자 배열 주위에 래퍼 클래스를 만들었습니다. 정확히 4 바이트의 메모리가 있고 그 이하도 아닌 문자열입니다.

이 클래스를 생성 한 후에 다른 클래스의 std::vector에 다른 클래스로 감싸서 빌드하면 코드 유형이 문자열 유형이됩니다. 나는 이것이 좋은 접근법인지 모른다. 훨씬 더 편리하게 끝나지 만 더 많은 공간을 낭비하게 될 것이다.

그래서 코드를 게시하기 전에보다 체계적인 아이디어 목록을 작성하십시오.

  • 내 캐릭터 유형은 바이트도 아니고 코드 포인트 일 수도 있습니다. 나는 그것을 Go 언어의 것과 같은 룬 (rune)이라고 명명했다.
  • 일련의 분해 된 룬으로 구성된 문자열로, O1의 색인 생성 및 조각화를 수행합니다.
  • 룬은 이제 기본 클래스가 아니기 때문에 유니 코드 공백을 감지하는 방법으로 확장 될 수 있습니다. mysring[0].is_whitespace()
  • 그래 펜은 어떻게 처리해야할지 모르겠군요.

호기심 사실! 룬 클래스의 프로토 타입을 만드는 방법에 관한 이상한 점은 항상 UTF8로 인쇄된다는 것입니다. 내 룬은 int32가 아니기 때문에 4 바이트 문자열이므로 흥미로운 속성이 있습니다.

내 코드 :

class rune { 
    char data[4] {}; 
public: 
    rune(char c) { 
     data[0] = c; 
    } 

    // This constructor needs a string, a position and an offset! 
    rune(std::string const & s, size_t p, size_t n) { 
     for (size_t i = 0; i < n; ++i) { 
      data[i] = s[p + i]; 
     } 
    } 

    void swap(rune & other) { 
     rune t = *this; 
     *this = other; 
     other = t; 
    } 

    // Output as UTF8! 
    friend std::ostream & operator <<(std::ostream & output, rune input) { 
     for (size_t i = 0; i < 4; ++i) { 
      if (input.data[i] == '\0') { 
       return output; 
      } 
      output << input.data[i]; 
     } 
     return output; 
    } 
}; 

오류 처리 아이디어 : 나는 C++에서 예외를 사용하고 싶지 않아요

. 내 생각에, 생성자가 실패하면 룬을 4 '\0'으로 초기화 한 다음 실행의 첫 번째 바이트가 '\0' 일 경우 bool 연산자를 명시 적으로 오버로드하여 false를 반환합니다. 간단하고 사용하기 쉽습니다.

그래서 생각은? 의견? 다른 접근법?

룬 문자열이 많은 경우에도 적어도 룬 문자 유형이 있습니다. 작고 빠른 복사. :)

+2

왜 "룬"을 저장하기 위해'char32_t'를 사용하지? –

+0

어떻게 사용합니까? 지난 번에 내가 그곳에 대한 많은 정보가 없다는 것을 확인했습니다. –

+2

[char32_t] (http://en.cppreference.com/w/cpp/language/types) "형식으로 UTF-32 문자 표현을 입력해야하며 UTF-32 코드 단위 (32 비트)를 나타낼만큼 충분히 커야합니다. 그것은'std :: uint_least32_t'와 같은 크기, 부호, 정렬을 가지고 있지만 구별되는 형식입니다. " –

답변

0

바퀴를 재발 명하려는 것 같습니다. 바이트 인코딩 된 배열로 코드 포인트의 배열

  • 으로

    • :

      은 물론,이 텍스트에 대해 생각할 필요가 가지 방법이 있습니다.일부 코드베이스에서

  • 은,이 두 표현은 동일합니다 (모든 인코딩은 기본적으로 char32_t 또는 unsigned int의 배열입니다). 일부에서는 ("가장"이라고 말하고 싶지만 나를 인용하지는 않습니다.) 인코딩 된 바이트 배열은 코드 구조가 데이터 구조에 배치되기 전에 가변 길이의 바이트로 변환되는 UTF-8을 사용합니다 .

    물론 많은 코드베이스는 유니 코드를 완전히 무시하고 데이터를 ASCII로 저장합니다. 나는 그것을 추천하지 않는다.

    데이터를 "랩 어라운드"하기 위해 클래스를 작성하는 것은 의미가 있지만 (rune이라고 부르지는 않지만, 단지 codepoint이라고 부름), 당신의 의미에 대해 생각해보십시오.

    • 당신은 (그리고 아마도해야한다) UTF-8로 인코딩 된 문자열, 모든 std::string 's의 치료 및 텍스트 처리하기위한 기본 인터페이스로이 선호 할 수 있습니다. 대부분의 외부 인터페이스는 안전합니다. 실패 할 수있는 유일한 시간은 UTF-16 입력과 인터페이싱 할 때 뿐이지 만, 그 경우에 대소 문자를 쓸 수 있습니다. 또한 일반적인 문자열 규칙을 따르면서 가장 많은 메모리를 절약 할 수 있습니다. 사전 적으로 비교 가능하다. 이것은 큰 것이다.) 내가 코드를 작성해야했다 동안
    • 당신은 코드 포인트 형태의 데이터로 작업해야하는 경우, 다음 구조체를 작성하려는 (또는 클래스) 것은 다음과 같은 유용한 기능 및 생성자
      • 으로 codepoint라고 코드 포인트 형식 (특히 글꼴 렌더러의 경우)으로 텍스트를 처리하는 경우 이 아니며 텍스트를 저장하는 방법입니다. 텍스트를 코드 포인트로 저장하면 나중에 UTF-8 또는 ASCII로 인코딩 된 문자열과 비교할 때 문제가 발생합니다.

    코드 :

    struct codepoint { 
        char32_t val; 
        codepoint(char32_t _val = 0) : val(_val) {} 
        codepoint(std::string const& s); 
        codepoint(std::string::const_iterator begin, std::string::const_iterator end); 
        //I don't know the UTF-8→codepoint conversion off-hand. There are lots of places 
        //online that show how to do this 
    
        std::string to_utf8() const; 
        //Again, look up an algorithm. They're not *too* complicated. 
        void append_to_string_as_utf8(std::string & s) const; 
        //This might be more performant if you're trying to reduce how many dynamic memory 
        //allocations you're making. 
    
        //codepoint(std::wstring const& s); 
        //std::wstring to_utf16() const; 
        //void append_to_string_as_utf16(std::wstring & s) const; 
    
        //Anything else you need, equality operator, comparison operator, etc. 
    }; 
    
    +0

    "모든 std :: string은 UTF-8로 인코딩 된 문자열로 취급 될 수 있습니다. Windows라고하는 거의 알려지지 않은 OS가 있습니다. –

    +1

    @ n.m. 여전히 기본 저장 매체로 UTF-8 문자열을 권장하고 UTF-16 → UTF-8 또는 UTF-8 → UTF-16 변환으로 WinOS 시스템 호출을 둘러 쌀 수 있습니다. 가장 오류가 발생하기 쉬운 솔루션입니다. – Xirema

    +0

    사실, char32_t가 정수에 대한 별칭으로 구현되는 것이 좋습니다. 내 클래스는 배열이며, 배열처럼 동작합니다. 나중에 비교할 특별한 공백 문자를 저장하고 싶다면''\ xe3 \ x80 \ x80 "'으로 초기화 한 다음 비교할 수 있습니다. 트릭은'std :: string'을'std :: vector '으로 변환하는 것입니다. 분명히 유효성 검사를 수행해야합니다. 그러나 대부분의 경우 그것은 올바르게 작동해야합니다. 코드 포인트 인덱스를 얻은 다음 문자열을'std :: vector '으로 나눕니다. 또한 UTF8로 인쇄됩니다! –