なぜSWIFTの文字列はクエリをインデックスできないのですか?


SWIFTという言語を扱うとき、一番面白い部分の一つが文字列です.私が大好きな42ソウルでは、Piscineの選考過程から学部課程まで数回の訓練をしなければならない.だからこそ、スウィフト独特の文字列資料構造が多くの好奇心を引き起こしたのかもしれない.

1.C、C++、Pythonとの比較


基本的に、CC++言語では、文字列は、前述のように、char型データの配列構造でメモリに格納される.もちろん、C++では、std::stringという非常に便利な資料型を使用することができ、いくつかの違いはあるが、コアは依然として同じである.
ここで、charタイプはAscii規格に準拠しているため、1ワードあたり1バイトしか記憶できない.
パイソンは少し違います.まず、文字列オブジェクトとしてメモリにロードし、sys.getsizeof()で1文字がメモリにロードされた数をチェックすると、アルファベットが1バイトで格納され、ハングルがUnicodeで格納されているので、2バイトで格納されていることがわかります.
  • Pythonで文字のメモリ使用状況をチェック
  • import sys
    
    en_str = "A"
    ko_str = "ㄱ"
    
    print(sys.getsizeof(en_str))	#49 + 1
    print(sys.getsizeof(ko_str))
    
    """ 
    [공식문서 해설]
    https://docs.python.org/ko/3/library/sys.html#sys.getsizeof
    [참고자료]
    https://wikidocs.net/15102
    """
  • C宣言およびクエリ文字列(スタティック割り当てスタックの場合)
  • char str[13] = "hello world!";
    printf("idx: 6, str: %c\n", str[6]);
  • C++での文字列の宣言とクエリー
  • std::string str = "hello world!";
    std::cout << "idx: 6, str: " << str[6] << std::endl;
  • Python宣言とクエリー
  • str = "hello world!"
    print("idx: 6, str: ", str[6])
    インデックスはランダムに作成され、hello world!文字列クエリから1文字が出力されます.すべての結果はidx: 6, str: wに出力されます.
    もちろん、Pythonの文字列オブジェクトは、1文字に1バイトしか格納されていないシーケンスではありませんが、それでもPythonはIntデータインデックスを使用して文字列にアクセスできます.

    2.では、SWIFTはどのように文字列を検索しますか?


    この質問をする前に、とても面白いビデオを見てみましょう.Ascii 코드유니코드(utf-8)の起源を説明するビデオで、ビデオの真ん中の細部は本当に面白いです.

    このビデオが必要なのは、アップルが文字列データ構造を実施する際にUnicode基準を遵守しているためで、文字列クエリーにも関係しています.swiftの正式なドキュメントを参照してください
    返され、SWIFTで整数インデックスで文字列がクエリされた場合?下のように間違いを吐き出す.

    ではSWIFTではどのように問い合わせるべきか、以下のようにString.Indexを使ってアクセスするべきです.
    // 선언
    let str = "hello world!"
    
    // 조회
    str[str.startIndex]	// 'h'
    str[str.endIndex]	// '!' 가 나올지 알았겠지만 바로 에러 뜨지롱
    
    var idx = str.index(str.startIndex, offsetBy: 6)
    str[idx]		// 'w'
    
    
    // 이터레이터(반복문)를 인덱스처럼 뽑아 사용하려면 indicies 메소드 사용해야한다.
    for c in str.indices {
        print(str[c])	// Index(_rawBits:) 값이 출력된다. 
    }
    
    これを見て、心の奥から一言.

    どうして。

    hello world!という文字列からwにアクセスし、Pythonではstr[6]が終了し、SWIFTではstr[str.index(str.startIndex, offsetBy: 6)のみが1文字にアクセスできる.表面的にはstr str str...変数名を3回使用します.
    明らかに、CC++言語から整数インデックスへの有効な方法はすでにあり、現代言語のパターンを混合したSwiftでは、なぜこのような低効率が現れるのだろうか.

    3.SWIFTの文字記憶構造


    前の言語の文字列には、インデックスごとに同じサイズのデータ値があります.SWIFT公式文書2Character型のデータは、拡張文字セットとして表される.

    Extended Grapheme Clusters


    SWIFTでは、Character資料型は「人が読める一字」が標準です.したがって、1つのワードに複数のUnicodeスカラー値を持つことができるため、各ワードのメモリが異なる場合があります.
    上記の正式な文書では、1つのCharacterタイプが複数のスカラー値を有することができることを例に挙げた.
    let precomposed: Character = "\u{D55C}"                  // 한
    let decomposed: Character = "\u{1112}\u{1161}\u{11AB}"   // ᄒ, ᅡ, ᆫ
    // precomposed is 한, decomposed is 한
    例では、の組み合わせの文字は、Unicodeスカラー値を有し、以下、3つのUnicodeスカラー値を有する.しかし、重要なのは、両方が同じCharacterであることです.
    そのため、他の言語のようにstr[6]に近づこうとすると、具体的な意図が不明になる.
    実際には、str[6]から6の数字がアレイのようにメモリを消費し、6番目のインデックスを表示するためです.SWIFTのように、各文字に複数のUnicodeスカラー値がある場合、各文字のメモリは異なるため、iとは限らない.
    インデックスでアクセスできないと言ったら、また疑問があります.つまり、String.Indexに戻るindex(_:offsetBy:)メソッドです.この方法は、swiftから供給される第1のパラメータoffsetBy:の位置を返す.
    重要なのは、ここの"offsetBy: 만큼 떨어진"はどういう意味ですか.インデックスでクエリーできないと言うので、この方法ではインデックスでクエリーした「らしい」はどうしても表示されません.

    まずStringIndexが何なのかから公式文書を見てみましょう。



    上記の公式文書によれば,String資料型におけるIndex構造体は双方向集合プロトコルを用いた構造体である.

    BidirectionalCollection & RandomAccessCollection

    String.Index構造体は、BidirectionalCollectionプロトコル、すなわち文字列のインデックスルックアップ構造が양방향 순회방식である.つまり、無条件に自分の前後方向を探索するしかない.
    通常、ランダム・アクセス・メソッドを使用して、文字列内の任意の距離の要素をO(1)の時間複雑度に参照し、クエリー・パフォーマンスを有します.しかし、アップルはこの性能を放棄したようで、すべての字に柔軟なメモリサイズを提供するわけではありません.BidirectionalCollectionプロトコルを使用してインデックスアクセスを実現するには、O(n)の時間的複雑さが必要です.
    したがって、文字列の始点から任意の距離の要素を参照するには、すべての前のステップを経験する必要があります.
    この方法で実現され、各文字セットに対応するdistanceが計算される.もちろん、よろしければutf-8, utf-16, unicodeScalarsで計算することもできます.

    4.結論


    SWIFTは、拡張された文字セット(Extended Grapheme Clusters)を使用して、さまざまな言語と特殊な文字に対応し、各文字に柔軟なメモリサイズを持たせ、任意の点から大きな要素を双方向にナビゲートして文字列の要素に近づきます.
    SWIFTのこのような文字記憶構造は、限られたメモリ内で世界中の人々にサービスを提供する悩みの中で生まれた.
    もちろんそれもあまりよくありません.