web-dev-qa-db-ja.com

golang文字列の文字を数える

外出先で「文字」を数えようとしています。つまり、文字列に印刷可能な「グリフ」または「構成文字」(または誰かが通常文字と考えるもの)が1つ含まれている場合、1を数えたいと思います。たとえば、文字列「こんにちは、世???」 ?????????界」は、11文字あるため、11と数える必要があります。人間はこれを見て、11個のグリフがあると言います。

utf8.RuneCountInString()は、ASCII、アクセント、アジア文字、さらには絵文字を含め、ほとんどの場合にうまく機能します。ただし、私が理解しているように、ルーンは文字ではなくコードポイントに対応します。基本的な絵文字を使おうとすると機能しますが、肌の色が異なる絵文字を使用すると、カウントが間違ってしまいます: https://play.golang.org/p/aFIGsB6MsO

私が読んだものから ここここ 以下はうまくいくはずですが、それでも正しい結果が得られていないようです(過大評価されています):

func CountCharactersInString(str string) int {
    var ia norm.Iter
    ia.InitString(norm.NFC, str)
    nc := 0
    for !ia.Done() {
        nc = nc + 1
        ia.Next()
    }
    return nc
}

これも機能しません:

func GraphemeCountInString(str string) int {
    re := regexp.MustCompile("\\PM\\pM*|.")
    return len(re.FindAllString(str, -1))
}

私はObjectiveCでこれに似たものを探しています:

+ (NSInteger)countCharactersInString:(NSString *) string {
    // --- Calculate the number of characters enterd by user and update character count label
    NSInteger count = 0;
    NSUInteger index = 0;
    while (index < string.length) {
        NSRange range = [string rangeOfComposedCharacterSequenceAtIndex:index];
        count++;
        index += range.length;
    }
    return count;
 }
11
Bjorn Roche

これを可能にするパッケージを作成しました: https://github.com/rivo/unisegnicode Standard Annex#29 で指定されたルールに従って文字列を分割します。これは、探しているものです。これがあなたの場合にそれをどのように使うかです:

package main

import (
    "fmt"

    "github.com/rivo/uniseg"
)

func main() {
    fmt.Println(uniseg.GraphemeClusterCount("Hello, 世????????????界"))
}

これにより、期待どおりに11が出力されます。

5
Oliver

strings.Count を試しましたか?

package main

import (
     "fmt"
     "strings"
 )

 func main() {
     fmt.Println(strings.Count("Hello, 世????????界", "????")) // Returns 2
 }
5
p_mcp

APIドキュメントの例への参照。 https://golang.org/pkg/unicode/utf8/#example_DecodeLastRuneInString

package main

import (
    "fmt"
    "unicode/utf8"
)

func main() {
    str := "Hello, 世????界"
    count := 0
    for len(str) > 0 {
        r, size := utf8.DecodeLastRuneInString(str)
        count++
        fmt.Printf("%c %v\n", r, size)

        str = str[:len(str)-size]
    }
    fmt.Println("count:",count)
}
3
Jiang YD