Introduction
Line filters in Go are programs that read input from standard input (stdin), process each line of input, and then write the output to standard output (stdout). They are commonly used for text processing tasks such as filtering, transforming, and analyzing text data. In this chapter, you will learn the basics of creating line filters in Go, including reading input, processing lines, and writing output.
Reading from Standard Input
To read input from stdin, you can use the bufio
package, which provides a buffered reader that makes it easy to read lines of text.
Example: Reading Lines from Standard Input
Example:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
fmt.Println(line)
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "Error reading input:", err)
os.Exit(1)
}
}
In this example, the program reads lines from stdin and prints them to stdout. The scanner.Err
method checks for errors during reading.
Processing Lines
You can add logic to process each line as it is read. This can include filtering lines based on certain criteria, transforming the text, or performing other operations.
Example: Filtering Lines
Example:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, "Go") {
fmt.Println(line)
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "Error reading input:", err)
os.Exit(1)
}
}
In this example, the program reads lines from stdin and prints only those lines that contain the substring "Go".
Example: Transforming Lines
Example:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
upperLine := strings.ToUpper(line)
fmt.Println(upperLine)
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "Error reading input:", err)
os.Exit(1)
}
}
In this example, the program reads lines from stdin, converts each line to uppercase, and then prints it to stdout.
Writing to Standard Output
Writing to stdout can be done using the fmt
package, as shown in the previous examples. For more complex output formatting or buffering, you can use the bufio
package.
Example: Writing with Buffered Writer
Example:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
for scanner.Scan() {
line := scanner.Text()
upperLine := strings.ToUpper(line)
writer.WriteString(upperLine + "\n")
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "Error reading input:", err)
os.Exit(1)
}
}
In this example, the program uses a buffered writer to write each transformed line to stdout, ensuring efficient writing.
Handling Command-Line Arguments
Many line filters accept command-line arguments to control their behavior. You can use the os
package to access these arguments.
Example: Filtering Lines with Command-Line Arguments
Example:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "Usage: go run main.go <substring>")
os.Exit(1)
}
substring := os.Args[1]
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
line := scanner.Text()
if strings.Contains(line, substring) {
fmt.Println(line)
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "Error reading input:", err)
os.Exit(1)
}
}
In this example, the program takes a substring as a command-line argument and prints only those lines from stdin that contain the specified substring.
Error Handling
Proper error handling is crucial for robust programs. Always check for errors when reading from stdin and writing to stdout.
Example: Comprehensive Error Handling
Example:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
writer := bufio.NewWriter(os.Stdout)
defer writer.Flush()
for scanner.Scan() {
line := scanner.Text()
_, err := writer.WriteString(line + "\n")
if err != nil {
fmt.Fprintln(os.Stderr, "Error writing output:", err)
os.Exit(1)
}
}
if err := scanner.Err(); err != nil {
fmt.Fprintln(os.Stderr, "Error reading input:", err)
os.Exit(1)
}
}
In this example, the program handles errors during both reading and writing, ensuring that any issues are reported and the program exits gracefully.
Conclusion
Line filters in Go are powerful tools for processing text data. By reading from stdin, processing each line, and writing to stdout, you can create flexible and efficient text processing programs. Proper error handling and the use of command-line arguments can make your line filters more robust and user-friendly. With these techniques, you can build a wide range of text processing tools in Go.