https://github.com/maxim2266/strit
Package strit introduces a new type of string iterator, along with a number of iterator constructors, wrappers and combinators.
https://github.com/maxim2266/strit
fluent-interface function-composition golang iteration pipeline-framework string-processing
Last synced: 2 months ago
JSON representation
Package strit introduces a new type of string iterator, along with a number of iterator constructors, wrappers and combinators.
- Host: GitHub
- URL: https://github.com/maxim2266/strit
- Owner: maxim2266
- License: bsd-3-clause
- Created: 2017-03-19T20:35:26.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2021-07-22T21:41:09.000Z (almost 4 years ago)
- Last Synced: 2025-04-14T07:06:44.314Z (2 months ago)
- Topics: fluent-interface, function-composition, golang, iteration, pipeline-framework, string-processing
- Language: Go
- Homepage:
- Size: 34.2 KB
- Stars: 84
- Watchers: 5
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# strit
[](https://pkg.go.dev/github.com/maxim2266/strit)
[](https://goreportcard.com/report/github.com/maxim2266/strit)
[](https://opensource.org/licenses/BSD-3-Clause)Package `strit` (STRing ITerator) assists in development of string processing pipelines by providing a simple
iteration model that allows for easy composition of processing stages.### Motivation
Suppose we want to develop a function that reads a file line by line, removes leading and trailing
whitespace from each line, selects only non-empty lines that also do not start with the `#` symbol, and
stores those lines in a slice of strings. Using the Go standard library one possible implementation
of the function may look like this:
```Go
func ReadConfig(fileName string) ([]string, error) {
file, err := os.Open(fileName)if err != nil {
return nil, err
}defer file.Close()
var res []string
src := bufio.NewScanner(file)for src.Scan() {
line := bytes.TrimSpace(src.Bytes())if len(line) > 0 && line[0] != '#' {
res = append(res, string(line))
}
}if err = src.Err(); err != nil {
return nil, err
}return res, nil
}
```
Using `strit` package the implementation can be simplified down to:
```Go
func ReadConfig(fileName string) ([]string, error) {
return strit.FromFile(fileName).
Map(bytes.TrimSpace).
Filter(strit.Not(strit.Empty).AndNot(strit.StartsWith("#"))).
Strings()
```
### Features
* A number of iterator constructors for reading text from a variety of sources:
* `io.Reader`:
[`FromReader`](https://godoc.org/github.com/maxim2266/strit#FromReader)
[`FromReaderSF`](https://godoc.org/github.com/maxim2266/strit#FromReaderSF)
* `io.ReadCloser`:
[`FromReadCloser`](https://godoc.org/github.com/maxim2266/strit#FromReadCloser)
[`FromReadCloserSF`](https://godoc.org/github.com/maxim2266/strit#FromReadCloserSF)
* `[]byte`:
[`FromBytes`](https://godoc.org/github.com/maxim2266/strit#FromBytes)
[`FromBytesSF`](https://godoc.org/github.com/maxim2266/strit#FromBytesSF)
* `string`:
[`FromString`](https://godoc.org/github.com/maxim2266/strit#FromString)
[`FromStringSF`](https://godoc.org/github.com/maxim2266/strit#FromStringSF)
* `[]string`:
[`FromStrings`](https://godoc.org/github.com/maxim2266/strit#FromStrings)
* Disk file:
[`FromFile`](https://godoc.org/github.com/maxim2266/strit#FromFile)
[`FromFileSF`](https://godoc.org/github.com/maxim2266/strit#FromFileSF)
* Directory listing:
[`FromDir`](https://godoc.org/github.com/maxim2266/strit#FromDir)
* Recursive directory listing:
[`FromDirWalk`](https://godoc.org/github.com/maxim2266/strit#FromDirWalk)
* External command output:
[`FromCommand`](https://godoc.org/github.com/maxim2266/strit#FromCommand)
[`FromCommandSF`](https://godoc.org/github.com/maxim2266/strit#FromCommandSF)
* Mapping and filtering primitives:
[`Filter`](https://godoc.org/github.com/maxim2266/strit#Iter.Filter)
[`GenMap`](https://godoc.org/github.com/maxim2266/strit#Iter.GenMap)
[`Map`](https://godoc.org/github.com/maxim2266/strit#Iter.Map)
* Sequence limiting functions:
[`Skip`](https://godoc.org/github.com/maxim2266/strit#Iter.Skip)
[`SkipWhile`](https://godoc.org/github.com/maxim2266/strit#Iter.SkipWhile)
[`Take`](https://godoc.org/github.com/maxim2266/strit#Iter.Take)
[`TakeWhile`](https://godoc.org/github.com/maxim2266/strit#Iter.TakeWhile)
* Search function:
[`FirstNonEmpty`](https://godoc.org/github.com/maxim2266/strit#Iter.FirstNonEmpty)
* Piping iterator output through an external command:
[`Pipe`](https://godoc.org/github.com/maxim2266/strit#Iter.Pipe)
[`PipeSF`](https://godoc.org/github.com/maxim2266/strit#Iter.PipeSF)
* Iterator chaining (sequential combination):
[`Chain`](https://godoc.org/github.com/maxim2266/strit#Chain)
* Iterator merging (parallel combination):
[`Merge`](https://godoc.org/github.com/maxim2266/strit#Merge)
* Output collectors that invoke the given iterator and write the result to various destinations:
* `string`:
[`String`](https://godoc.org/github.com/maxim2266/strit#Iter.String)
[`Join`](https://godoc.org/github.com/maxim2266/strit#Iter.Join)
* `[]string`:
[`Strings`](https://godoc.org/github.com/maxim2266/strit#Iter.Strings)
* `[]byte`:
[`Bytes`](https://godoc.org/github.com/maxim2266/strit#Iter.Bytes)
[`JoinBytes`](https://godoc.org/github.com/maxim2266/strit#Iter.JoinBytes)
* `io.Writer`:
[`WriteTo`](https://godoc.org/github.com/maxim2266/strit#Iter.WriteTo)
[`WriteSepTo`](https://godoc.org/github.com/maxim2266/strit#Iter.WriteSepTo)
* Disk file:
[`WriteToFile`](https://godoc.org/github.com/maxim2266/strit#Iter.WriteToFile)
[`WriteSepToFile`](https://godoc.org/github.com/maxim2266/strit#Iter.WriteSepToFile)
* Predicates and predicate combinators for use with `Filter`:
[`Empty`](https://godoc.org/github.com/maxim2266/strit#Empty)
[`StartsWith`](https://godoc.org/github.com/maxim2266/strit#StartsWith)
[`EndsWith`](https://godoc.org/github.com/maxim2266/strit#EndsWith)
[`Not`](https://godoc.org/github.com/maxim2266/strit#Not)
[`And`](https://godoc.org/github.com/maxim2266/strit#Pred.And)
[`AndNot`](https://godoc.org/github.com/maxim2266/strit#Pred.AndNot)
[`Or`](https://godoc.org/github.com/maxim2266/strit#Pred.Or)
[`OrNot`](https://godoc.org/github.com/maxim2266/strit#Pred.OrNot)
* Basic parsing supported via [`Parse`](https://godoc.org/github.com/maxim2266/strit#Iter.Parse) function.### More examples:
* Naïve `grep`:
```Go
func main() {
_, err := strit.FromReader(os.Stdin).
Filter(regexp.MustCompile(os.Args[1]).Match).
WriteSepTo(os.Stdout, "\n")if err != nil {
os.Stderr.WriteString(err.Error() + "\n")
os.Exit(1)
}
}
```
* Recursively find all the filesystem entries matching the given regular expression:
```Go
func selectEntries(root string, re *regexp.Regexp) ([]string, error) {
return FromDirWalk(root, nil).Filter(re.Match).Strings()
}
```
* Build a list of `.flac` files in the given directory, annotating each name with its corresponding
track number from FLAC metadata:
```Go
func namesWithTrackNumbers(dir string) ([]string, error) {
return strit.FromDir(dir, func(info os.FileInfo) bool { return info.Mode().IsRegular() }).
Filter(strit.EndsWith(".flac")).
GenMap(prependTrackNo).
Strings()
}func prependTrackNo(file []byte) ([]byte, error) {
name := string(file)no, err := strit.FromCommand(exec.Command("metaflac", "--list", "--block-type=VORBIS_COMMENT", name)).
FirstNonEmpty(func(s []byte) []byte {
if m := match(s); len(m) == 2 {
return m[1]
}return nil
}).
String()if err != nil {
return nil, err
}if len(no) == 0 {
return []byte("???: " + filepath.Base(name)), nil
}return []byte(no + ": " + filepath.Base(name)), nil
}var match = regexp.MustCompile(`tracknumber=([[:digit:]]+)$`).FindSubmatch
```### Project status
The project is in a beta state. Tested on Linux Mint 19.1, with Go version 1.12.
Should also work on other platforms supported by Go runtime, but currently this is not very well tested.##### License: BSD