2017-11-11 6 views

答えて

4

これは完璧です。しかし、最後の文字が改行文字でない場合は、出現回数に1を加えなければならないことを忘れないでください。行数(最後の行は改行で終わらないかもしれません)。

カウントしている部分文字列が1文字(単一のrune)であるため、(文字列をカウントする代わりに)この1文字の出現のみをカウントするカスタムソリューションを作成することができます。

func countRune(s string, r rune) int { 
    count := 0 
    for _, c := range s { 
     if c == r { 
      count++ 
     } 
    } 
    return count 
} 

(そのrune秒以上string値を反復処理上for range。)

そして、それをテストする(Go Playground上でそれを試してみてください):

fmt.Println(countRune("asdf\nasdf\nasdf\n", '\n')) // Prints 3 

それはこのように見えるかもしれませんこれは、UTF-8エンコーディングでbyteという単一のものであり、部分文字列の長さが部分文字列の数になるように既に最適化されているので、改行文字をより高速に数えることはできません1:あなたは「内部」バイトまたはエディタのルーン配列へのアクセス権を持っている場合は、この操作のパフォーマンスを向上させることができるもの

// Count counts the number of non-overlapping instances of substr in s. 
// If substr is an empty string, Count returns 1 + the number of Unicode code points in s. 
func Count(s, substr string) int { 
    if len(substr) == 1 && cpu.X86.HasPOPCNT { 
     return countByte(s, byte(substr[0])) 
    } 
    return countGeneric(s, substr) 
} 

func countByte(s string, c byte) int // ../runtime/asm_amd64.s 

(行のカウント)があるので、あなたはそのText()メソッドを呼び出す必要がありませんこれは、コンテンツのコピーを作成して返します。

1

最速の方法について質問するときは、Go testingパッケージベンチマーク機能を使用して測定する必要があります。例えば

strings.Countを用いてstringfor rangeループを使用lorem ipsumの行数をカウントし、stringbyteスライスからの変換の追加のコストを測定します。 byteスライス内の行数を数えることによって、byteスライスからstringオーバヘッドまでを避けることができます。

$ gotest lines_test.go -bench=. 
data: /home/peter/shakespeare.pg100.txt 5589889 
BenchmarkStringCount-4  30000000 57.3 ns/op  0 B/op 0 allocs/op 
BenchmarkStringByRune-4  3000000 563 ns/op  0 B/op 0 allocs/op 
BenchmarkBytesToString-4 10000000 173 ns/op  480 B/op 1 allocs/op 
BenchmarkBytesCount-4  20000000 61.2 ns/op  0 B/op 0 allocs/op 

lines_test.go

package main 

import (
    "bytes" 
    "strconv" 
    "strings" 
    "testing" 
) 

func linesStringCount(s string) string { 
    n := strings.Count(s, "\n") 
    if len(s) > 0 && !strings.HasSuffix(s, "\n") { 
     n++ 
    } 
    return strconv.Itoa(n) 
} 

func linesStringByRune(s string) string { 
    n := 0 
    for _, r := range s { 
     if r == '\n' { 
      n++ 
     } 
    } 
    if len(s) > 0 && !strings.HasSuffix(s, "\n") { 
     n++ 
    } 
    return strconv.Itoa(n) 
} 

func linesBytesCount(s []byte) string { 
    nl := []byte{'\n'} 
    n := bytes.Count(s, nl) 
    if len(s) > 0 && !bytes.HasSuffix(s, nl) { 
     n++ 
    } 
    return strconv.Itoa(n) 
} 

var data = []byte(`Lorem ipsum dolor sit amet, consectetur adipiscing elit, 
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. 
Ut enim ad minim veniam, 
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. 
Excepteur sint occaecat cupidatat non proident, 
sunt in culpa qui officia deserunt mollit anim id est laborum.`) 

func BenchmarkStringCount(b *testing.B) { 
    text := string(data) 
    b.ReportAllocs() 
    b.ResetTimer() 
    for i := 0; i < b.N; i++ { 
     _ = linesStringCount(text) 
    } 
} 

func BenchmarkStringByRune(b *testing.B) { 
    text := string(data) 
    b.ReportAllocs() 
    b.ResetTimer() 
    for i := 0; i < b.N; i++ { 
     _ = linesStringByRune(text) 
    } 
} 

func BenchmarkBytesToText(b *testing.B) { 
    b.ReportAllocs() 
    b.ResetTimer() 
    for i := 0; i < b.N; i++ { 
     _ = string(data) 
    } 
} 

func BenchmarkBytesCount(b *testing.B) { 
    text := data 
    b.ReportAllocs() 
    b.ResetTimer() 
    for i := 0; i < b.N; i++ { 
     _ = linesBytesCount(text) 
    } 
} 
関連する問題