[go] お客様の中にGoを極めた方はいらっしゃいませんかー?

golangでも同じことをやってみた

[c#] SJISというかCP932とかいう呪い

c#でのcp932で化けてしまう一部キャラクタを変換するやつ。それをgoで書いてみたのだけど……。なんだろ、遅い。正規表現は他言語と同じく遅いようで、RegexpではなくReplacer使えーとかそこらへんは考慮して書いたのだが。stopwatchの精度もスリープで確認したりなんだりで問題なさそう。未使用メソッドがあったり、処理の1,2,3を順にループさせたりするとどんどん遅くなる(なので未使用~についてはコメントアウトしてる)のが謎い。

👺 < 処理が遅い!

4826            // -> goでのこのミリセカンド表記はc#版のほうでいうと
00:00:04.0826   // -> これと同値

最終結果は同じだが、文字化け(マッピングできないキャラ)が来るとそこで試合終了っぽい。

結果

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
    "time"

    "golang.org/x/text/encoding/japanese"
    "golang.org/x/text/transform"
)

// ループの外でReplacerを持つようにした
var rep *strings.Replacer

func main() {
    fmt.Println("start")
    // ファイル読み込み
    list := getFileData()
    /*list2 := make([]string, len(list))
    copy(list2, list)
    list3 := make([]string, len(list))
    copy(list3, list)*/
    // 処理
    start1 := time.Now()
    // ループの外でReplacerを持つようにした
    rep = strings.NewReplacer("〜", "~", "−", "-", "¢", "¢", "£", "£", "¬", "¬", "—", "―", "‖", "∥")
    for i := 0; i < 1000000; i++ {
        replaceUnmappingChars1(list)
    }
    stop1 := time.Now()
    fmt.Println(stop1.Sub(start1).Milliseconds())
    // ファイル書き込み
    outputFile(list)
    fmt.Println("end")
}

// replace unmapping chars3 -> 8293
/*func replaceUnmappingChars3(list []string) {
    for i, str := range list {
        sl := strings.Split(str, "")
        length := len(sl)
        var rep string
        for j := 0; j < length; j++ {
            if sl[j] == "〜" {
                rep += "~"
            } else if sl[j] == "−" {
                rep += "-"
            } else if sl[j] == "¢" {
                rep += "¢"
            } else if sl[j] == "£" {
                rep += "£"
            } else if sl[j] == "¬" {
                rep += "¬"
            } else if sl[j] == "—" {
                rep += "―"
            } else if sl[j] == "‖" {
                rep += "∥"
            } else {
                rep += sl[j]
            }
        }
        list[i] = rep
    }
}*/

// replace unmapping chars2 -> 100万回 9946
/*func replaceUnmappingChars2(list []string) {
    for i, str := range list {
        var rep string
        for _, c := range str {
            if string(c) == "〜" {
                rep += "~"
            } else if string(c) == "−" {
                rep += "-"
            } else if string(c) == "¢" {
                rep += "¢"
            } else if string(c) == "£" {
                rep += "£"
            } else if string(c) == "¬" {
                rep += "¬"
            } else if string(c) == "—" {
                rep += "―"
            } else if string(c) == "‖" {
                rep += "∥"
            } else {
                rep += string(c)
            }
        }
        list[i] = rep
    }
}*/

// replace unmapping chars -> 100万回 4826
func replaceUnmappingChars1(list []string) {
    for i, data := range list {
        //rep := strings.NewReplacer("〜", "~", "−", "-", "¢", "¢", "£", "£", "¬", "¬", "—", "―", "‖", "∥")
        list[i] = rep.Replace(data)
    }
}

// GetFileData return list
func getFileData() []string {
    // file open
    file, err := os.Open("./source.txt")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    defer file.Close() // c#でのusing - disposeみたいな? todo:あとでもっとよく調べる
    // file read
    var data []string
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        data = append(data, scanner.Text())
    }
    if err := scanner.Err(); err != nil { // どうやったらここに来るんだ?
        fmt.Println(err)
        os.Exit(1)
    }
    return data
}

// outputFile
func outputFile(list []string) {
    // file create todo:上書きっぽい(あとでよく見る)
    file, err := os.Create("./destination_sjis_fix.txt")
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    defer file.Close()
    // data write
    writer := bufio.NewWriter(transform.NewWriter(file, japanese.ShiftJIS.NewEncoder()))
    for _, data := range list {
        _, err := writer.WriteString(data + "\n") // やっぱり普通はここで変換するよね(c#でも書いたのでこっちにも)
        if err != nil {
            fmt.Println(err)
            os.Exit(1)
        }
    }
    writer.Flush() // buf(debuggerでみた)の中にWriteStringで溜めてFlushで一気に書くっぽい
}

なんか根本的にミスってるのかなー。わからん。ベンチマークメソッド?みたいなのがあるからそっちでやらないとダメなのかなー。