Go 練習01.統計文本行出現頻次/查找重複的行

從標準輸入讀取文本,統計相同文本出現的次數

package main
import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    // 統計文本 {"文本1":5 }  即`文本1`出現5次
    counts := make(map[string]int)
    
    // os.Stdin 是標準輸入, 就是屏幕終端輸入的信息
    // bufio.NewScanner 創建並返回從 `標準輸入中` 讀取數據的Scanner
    // Scanner 類型是什麼呢?提供了方便的讀取數據的接口,如從換行符分隔的文本里讀取每一行 
    input := bufio.NewScanner(os.Stdin)
    
    // 調用Scanner.Scan()返回的是true/false
    // 他判斷的是 是否有輸入, ctrl+D 則返回false,他是阻塞的
    // 當它執行後,調用input.Text() 就可以獲取到值,
    // 如果連續執行兩次Scanner.Scan(),則第一次的值就會被跳過
    // 文檔中有個token的概念,它就是讓Scanner的掃描位置移動到下一個token,
    // 如果你不使用Bytes或Text方法獲得值,則會錯過。
    for input.Scan() {
        // 不用擔心沒有 ,我們設置的int類型 ,默認沒有初始值爲0
        counts[input.Text()]++
    }

    // ctrl+D 後上面的for循環會終止(不滿足循環條件)
    
    // 遍歷map key:value
    for line, n := range counts {
        if n >= 1 {
            fmt.Print(line,,n)
        }
    }
}

go run find.go 沒有參數,則從標準輸入中讀取數據

go run find.go 1.txt 2.txt ... 有參數,則從對應的文件中讀取數據

package main

import (
    "bufio"
    "fmt"
    "os"
)

func main() {
    counts := make(map[string]int)
    
    files := os.Args[1:]
    
    if len(files) == 0 {
        countLines(os.Stdin, counts)
    } else {
        for _, arg := range files {
            // os.Open打開文件
            f, err := os.Open(arg)
            if err != nil {
                // 標準錯誤輸出
                fmt.Fprintf(os.Stderr, "dup2: %v\n", err)
                continue
            }
            countLines(f, counts)
            f.Close()
        }
    }
    
    for line, n := range counts {
        if n >= 1 {
            fmt.Printf("%d\t%s\n", n, line)
        }
    }
}

func countLines(f *os.File, counts map[string]int) {
    input := bufio.NewScanner(f)
    for input.Scan() {
        counts[input.Text()]++
    }
}

只讀文件 不讀標準輸入,換一個方法讀取文件 io/ioutil

package main

import (
    "fmt"
    "io/ioutil"
    "os"
    "strings"
)

func main() {
    
    counts := make(map[string]int)
    
    for _, filename := range os.Args[1:] {
        // data 是 字節切片(byte slice)
        data, err := ioutil.ReadFile(filename)
        if err != nil {
            fmt.Fprintf(os.Stderr, "dup3: %v\n", err)
            continue
        }
        // 把切片轉成string, 使用Split分割,
        // 這裏最後一個元素爲"" 因爲最後一個是換行符,所以比預期的多一個""
        for _, line := range strings.Split(string(data), "\n") {
            counts[line]++
        }
    }
    
    for line, n := range counts {
        if n >= 1 {
            fmt.Printf("%d\t%s\n", n, line)
        }
    }
}

補充printf

%d          十進制整數
%x, %o, %b  十六進制,八進制,二進制整數。
%f, %g, %e  浮點數: 3.141593 3.141592653589793 3.141593e+00
%t          布爾:true或false
%c          字符(rune) (Unicode碼點)
%s          字符串
%q          帶雙引號的字符串"abc"或帶單引號的字符'c'
%v          變量的自然形式(natural format)
%T          變量的類型
%%          字面上的百分號標誌(無操作數)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章