Golang grep clone












1














I am trying to make a simple clone of the CMD line utility grep. I'm working on it just for fun and to practice GO. The thing is, I am trying to make it in a way that if several files are given at the command line, a different go routine is generated to speed up the process. The thing is, even so, standard grep still gets results faster by an amount of 60 % less processing time. ( Give or take)



Here it is the code for it.



Can you please provide some opinions about it?



package main


import (

"bufio"

"flag"

"fmt"

"io"

"os"

"path/filepath"

"regexp"

"sync"

)


type result struct {

Filename string

Line string

LineNumber int

Error error

}


var strRex string

var filenames string

var regRex *regexp.Regexp

var wg sync.WaitGroup

var allResults result

var verbose = false

var recursive string

var recursiveFileList string

var fileFilter string

var rexfileFilter *regexp.Regexp

var inverseSearch bool


func init() {

var rexError error

flag.StringVar(&strRex, "r", "", "Regular expresion to match against the input files")

flag.BoolVar(&verbose, "v", false, "It sets verbose output (Basically showing filename and line number for each match)")

flag.BoolVar(&inverseSearch, "i", false, "It does what you might expect.. reverse the search")

flag.StringVar(&recursive, "R", "", "Recursively find all files starting from the current folder and apply the given search to them")

flag.StringVar(&fileFilter, "FF", "", "Filter to be applied to the filenames when used recursevily")

flag.Parse()

if strRex == "" {

fmt.Fprintf(os.Stderr, "The '-r' (regular expression flag is mandatory)n")

os.Exit(1)

}

regRex, rexError = regexp.Compile(strRex)

if rexError != nil {

fmt.Fprintf(os.Stderr, "Your regex '%s' cant compile. Error : %s", strRex, rexError.Error())

os.Exit(2)

}

rexfileFilter, rexError = regexp.Compile(fileFilter)

if rexError != nil {

fmt.Fprintf(os.Stderr, "Your regex '%s' cant compile. Error : %s", rexfileFilter, rexError.Error())

os.Exit(3)

}

if recursive != "" {

var err error

filenames, err = walkDir(recursive)

if err != nil {

fmt.Fprintf(os.Stderr, "%s", err.Error())

}


} else {


filenames = flag.Args()

}


}


func main() {


stat, err := os.Stdin.Stat()

if err != nil {

fmt.Fprintf(os.Stderr, "There is an error reading from stdin : %s", err)

os.Exit(3)

}

if (stat.Mode() & os.ModeNamedPipe) != 0 {

grepStdin(os.Stdin, regRex)

} else {

chResults := make(chan *result, 4)

wg.Add(len(filenames))

for _, fn := range filenames {

go grep(fn, regRex, &wg, chResults)

}

go func(wait *sync.WaitGroup, ch chan<- *result) {

wg.Wait()

close(ch)

}(&wg, chResults)


for res := range chResults {

if verbose {

formatRes(res, 1)

} else {

formatRes(res, 2)

}


}

}

}


func grepStdin(ptr io.Reader, reg *regexp.Regexp) {

bf := bufio.NewScanner(ptr)

var lineno = 1


for bf.Scan() {

// There is no XOR in Golang, so you ahve to do this :

if line := bf.Text(); (reg.Match(byte(line)) && !inverseSearch) || (!reg.Match(byte(line)) && inverseSearch) {


formatRes(&result{

Line: line,

LineNumber: lineno,

Error: nil,

}, 3)

}

lineno++

}

}


func grep(file string, reg *regexp.Regexp, wait *sync.WaitGroup, ch chan<- *result) {

fd, err := os.Open(file)

if err != nil {

ch <- &result{

Filename: file,

Error: err,

}

}

bf := bufio.NewScanner(fd)

var lineno = 1


for bf.Scan() {

// There is no XOR in Golang, so you ahve to do this :

if line := bf.Text(); (reg.Match(byte(line)) && !inverseSearch) || (!reg.Match(byte(line)) && inverseSearch) {


ch <- &result{

Filename: file,

Line: line,

LineNumber: lineno,

Error: nil,

}

}

lineno++

}

wg.Done()

}


func formatRes(r *result, format int) {

if format == 1 {

if r.Error == nil {

fmt.Printf("%d - %s - %sn", r.LineNumber, r.Filename, r.Line)

} else {

fmt.Fprintf(os.Stderr, "%s - %s n", r.Filename, r.Error)

}

}

if format == 2 {

if r.Error == nil {

fmt.Printf("%sn", r.Line)

} else {

fmt.Fprintf(os.Stderr, "%s - %s n", r.Filename, r.Error)

}

}

if format == 3 {

if r.Error == nil {

fmt.Printf("%sn", r.Line)

} else {

fmt.Fprintf(os.Stderr, "%sn", r.Error)

}

}

}


func walkDir(path string) (string, error) {

list := make(string, 0, 50)

err := filepath.Walk(".",

func(path string, info os.FileInfo, err error) error {

if err != nil {

return err

}

if fileFilter != "" {

if rexfileFilter.Match(byte(filepath.Base(path))) {

list = append(list, path)

}

} else {

list = append(list, path)

}

return nil // Unreachable code

})

if err != nil {

return nil, err

}

return list, nil

}









share|improve this question







New contributor




Matias Barrios is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

























    1














    I am trying to make a simple clone of the CMD line utility grep. I'm working on it just for fun and to practice GO. The thing is, I am trying to make it in a way that if several files are given at the command line, a different go routine is generated to speed up the process. The thing is, even so, standard grep still gets results faster by an amount of 60 % less processing time. ( Give or take)



    Here it is the code for it.



    Can you please provide some opinions about it?



    package main


    import (

    "bufio"

    "flag"

    "fmt"

    "io"

    "os"

    "path/filepath"

    "regexp"

    "sync"

    )


    type result struct {

    Filename string

    Line string

    LineNumber int

    Error error

    }


    var strRex string

    var filenames string

    var regRex *regexp.Regexp

    var wg sync.WaitGroup

    var allResults result

    var verbose = false

    var recursive string

    var recursiveFileList string

    var fileFilter string

    var rexfileFilter *regexp.Regexp

    var inverseSearch bool


    func init() {

    var rexError error

    flag.StringVar(&strRex, "r", "", "Regular expresion to match against the input files")

    flag.BoolVar(&verbose, "v", false, "It sets verbose output (Basically showing filename and line number for each match)")

    flag.BoolVar(&inverseSearch, "i", false, "It does what you might expect.. reverse the search")

    flag.StringVar(&recursive, "R", "", "Recursively find all files starting from the current folder and apply the given search to them")

    flag.StringVar(&fileFilter, "FF", "", "Filter to be applied to the filenames when used recursevily")

    flag.Parse()

    if strRex == "" {

    fmt.Fprintf(os.Stderr, "The '-r' (regular expression flag is mandatory)n")

    os.Exit(1)

    }

    regRex, rexError = regexp.Compile(strRex)

    if rexError != nil {

    fmt.Fprintf(os.Stderr, "Your regex '%s' cant compile. Error : %s", strRex, rexError.Error())

    os.Exit(2)

    }

    rexfileFilter, rexError = regexp.Compile(fileFilter)

    if rexError != nil {

    fmt.Fprintf(os.Stderr, "Your regex '%s' cant compile. Error : %s", rexfileFilter, rexError.Error())

    os.Exit(3)

    }

    if recursive != "" {

    var err error

    filenames, err = walkDir(recursive)

    if err != nil {

    fmt.Fprintf(os.Stderr, "%s", err.Error())

    }


    } else {


    filenames = flag.Args()

    }


    }


    func main() {


    stat, err := os.Stdin.Stat()

    if err != nil {

    fmt.Fprintf(os.Stderr, "There is an error reading from stdin : %s", err)

    os.Exit(3)

    }

    if (stat.Mode() & os.ModeNamedPipe) != 0 {

    grepStdin(os.Stdin, regRex)

    } else {

    chResults := make(chan *result, 4)

    wg.Add(len(filenames))

    for _, fn := range filenames {

    go grep(fn, regRex, &wg, chResults)

    }

    go func(wait *sync.WaitGroup, ch chan<- *result) {

    wg.Wait()

    close(ch)

    }(&wg, chResults)


    for res := range chResults {

    if verbose {

    formatRes(res, 1)

    } else {

    formatRes(res, 2)

    }


    }

    }

    }


    func grepStdin(ptr io.Reader, reg *regexp.Regexp) {

    bf := bufio.NewScanner(ptr)

    var lineno = 1


    for bf.Scan() {

    // There is no XOR in Golang, so you ahve to do this :

    if line := bf.Text(); (reg.Match(byte(line)) && !inverseSearch) || (!reg.Match(byte(line)) && inverseSearch) {


    formatRes(&result{

    Line: line,

    LineNumber: lineno,

    Error: nil,

    }, 3)

    }

    lineno++

    }

    }


    func grep(file string, reg *regexp.Regexp, wait *sync.WaitGroup, ch chan<- *result) {

    fd, err := os.Open(file)

    if err != nil {

    ch <- &result{

    Filename: file,

    Error: err,

    }

    }

    bf := bufio.NewScanner(fd)

    var lineno = 1


    for bf.Scan() {

    // There is no XOR in Golang, so you ahve to do this :

    if line := bf.Text(); (reg.Match(byte(line)) && !inverseSearch) || (!reg.Match(byte(line)) && inverseSearch) {


    ch <- &result{

    Filename: file,

    Line: line,

    LineNumber: lineno,

    Error: nil,

    }

    }

    lineno++

    }

    wg.Done()

    }


    func formatRes(r *result, format int) {

    if format == 1 {

    if r.Error == nil {

    fmt.Printf("%d - %s - %sn", r.LineNumber, r.Filename, r.Line)

    } else {

    fmt.Fprintf(os.Stderr, "%s - %s n", r.Filename, r.Error)

    }

    }

    if format == 2 {

    if r.Error == nil {

    fmt.Printf("%sn", r.Line)

    } else {

    fmt.Fprintf(os.Stderr, "%s - %s n", r.Filename, r.Error)

    }

    }

    if format == 3 {

    if r.Error == nil {

    fmt.Printf("%sn", r.Line)

    } else {

    fmt.Fprintf(os.Stderr, "%sn", r.Error)

    }

    }

    }


    func walkDir(path string) (string, error) {

    list := make(string, 0, 50)

    err := filepath.Walk(".",

    func(path string, info os.FileInfo, err error) error {

    if err != nil {

    return err

    }

    if fileFilter != "" {

    if rexfileFilter.Match(byte(filepath.Base(path))) {

    list = append(list, path)

    }

    } else {

    list = append(list, path)

    }

    return nil // Unreachable code

    })

    if err != nil {

    return nil, err

    }

    return list, nil

    }









    share|improve this question







    New contributor




    Matias Barrios is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.























      1












      1








      1







      I am trying to make a simple clone of the CMD line utility grep. I'm working on it just for fun and to practice GO. The thing is, I am trying to make it in a way that if several files are given at the command line, a different go routine is generated to speed up the process. The thing is, even so, standard grep still gets results faster by an amount of 60 % less processing time. ( Give or take)



      Here it is the code for it.



      Can you please provide some opinions about it?



      package main


      import (

      "bufio"

      "flag"

      "fmt"

      "io"

      "os"

      "path/filepath"

      "regexp"

      "sync"

      )


      type result struct {

      Filename string

      Line string

      LineNumber int

      Error error

      }


      var strRex string

      var filenames string

      var regRex *regexp.Regexp

      var wg sync.WaitGroup

      var allResults result

      var verbose = false

      var recursive string

      var recursiveFileList string

      var fileFilter string

      var rexfileFilter *regexp.Regexp

      var inverseSearch bool


      func init() {

      var rexError error

      flag.StringVar(&strRex, "r", "", "Regular expresion to match against the input files")

      flag.BoolVar(&verbose, "v", false, "It sets verbose output (Basically showing filename and line number for each match)")

      flag.BoolVar(&inverseSearch, "i", false, "It does what you might expect.. reverse the search")

      flag.StringVar(&recursive, "R", "", "Recursively find all files starting from the current folder and apply the given search to them")

      flag.StringVar(&fileFilter, "FF", "", "Filter to be applied to the filenames when used recursevily")

      flag.Parse()

      if strRex == "" {

      fmt.Fprintf(os.Stderr, "The '-r' (regular expression flag is mandatory)n")

      os.Exit(1)

      }

      regRex, rexError = regexp.Compile(strRex)

      if rexError != nil {

      fmt.Fprintf(os.Stderr, "Your regex '%s' cant compile. Error : %s", strRex, rexError.Error())

      os.Exit(2)

      }

      rexfileFilter, rexError = regexp.Compile(fileFilter)

      if rexError != nil {

      fmt.Fprintf(os.Stderr, "Your regex '%s' cant compile. Error : %s", rexfileFilter, rexError.Error())

      os.Exit(3)

      }

      if recursive != "" {

      var err error

      filenames, err = walkDir(recursive)

      if err != nil {

      fmt.Fprintf(os.Stderr, "%s", err.Error())

      }


      } else {


      filenames = flag.Args()

      }


      }


      func main() {


      stat, err := os.Stdin.Stat()

      if err != nil {

      fmt.Fprintf(os.Stderr, "There is an error reading from stdin : %s", err)

      os.Exit(3)

      }

      if (stat.Mode() & os.ModeNamedPipe) != 0 {

      grepStdin(os.Stdin, regRex)

      } else {

      chResults := make(chan *result, 4)

      wg.Add(len(filenames))

      for _, fn := range filenames {

      go grep(fn, regRex, &wg, chResults)

      }

      go func(wait *sync.WaitGroup, ch chan<- *result) {

      wg.Wait()

      close(ch)

      }(&wg, chResults)


      for res := range chResults {

      if verbose {

      formatRes(res, 1)

      } else {

      formatRes(res, 2)

      }


      }

      }

      }


      func grepStdin(ptr io.Reader, reg *regexp.Regexp) {

      bf := bufio.NewScanner(ptr)

      var lineno = 1


      for bf.Scan() {

      // There is no XOR in Golang, so you ahve to do this :

      if line := bf.Text(); (reg.Match(byte(line)) && !inverseSearch) || (!reg.Match(byte(line)) && inverseSearch) {


      formatRes(&result{

      Line: line,

      LineNumber: lineno,

      Error: nil,

      }, 3)

      }

      lineno++

      }

      }


      func grep(file string, reg *regexp.Regexp, wait *sync.WaitGroup, ch chan<- *result) {

      fd, err := os.Open(file)

      if err != nil {

      ch <- &result{

      Filename: file,

      Error: err,

      }

      }

      bf := bufio.NewScanner(fd)

      var lineno = 1


      for bf.Scan() {

      // There is no XOR in Golang, so you ahve to do this :

      if line := bf.Text(); (reg.Match(byte(line)) && !inverseSearch) || (!reg.Match(byte(line)) && inverseSearch) {


      ch <- &result{

      Filename: file,

      Line: line,

      LineNumber: lineno,

      Error: nil,

      }

      }

      lineno++

      }

      wg.Done()

      }


      func formatRes(r *result, format int) {

      if format == 1 {

      if r.Error == nil {

      fmt.Printf("%d - %s - %sn", r.LineNumber, r.Filename, r.Line)

      } else {

      fmt.Fprintf(os.Stderr, "%s - %s n", r.Filename, r.Error)

      }

      }

      if format == 2 {

      if r.Error == nil {

      fmt.Printf("%sn", r.Line)

      } else {

      fmt.Fprintf(os.Stderr, "%s - %s n", r.Filename, r.Error)

      }

      }

      if format == 3 {

      if r.Error == nil {

      fmt.Printf("%sn", r.Line)

      } else {

      fmt.Fprintf(os.Stderr, "%sn", r.Error)

      }

      }

      }


      func walkDir(path string) (string, error) {

      list := make(string, 0, 50)

      err := filepath.Walk(".",

      func(path string, info os.FileInfo, err error) error {

      if err != nil {

      return err

      }

      if fileFilter != "" {

      if rexfileFilter.Match(byte(filepath.Base(path))) {

      list = append(list, path)

      }

      } else {

      list = append(list, path)

      }

      return nil // Unreachable code

      })

      if err != nil {

      return nil, err

      }

      return list, nil

      }









      share|improve this question







      New contributor




      Matias Barrios is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      I am trying to make a simple clone of the CMD line utility grep. I'm working on it just for fun and to practice GO. The thing is, I am trying to make it in a way that if several files are given at the command line, a different go routine is generated to speed up the process. The thing is, even so, standard grep still gets results faster by an amount of 60 % less processing time. ( Give or take)



      Here it is the code for it.



      Can you please provide some opinions about it?



      package main


      import (

      "bufio"

      "flag"

      "fmt"

      "io"

      "os"

      "path/filepath"

      "regexp"

      "sync"

      )


      type result struct {

      Filename string

      Line string

      LineNumber int

      Error error

      }


      var strRex string

      var filenames string

      var regRex *regexp.Regexp

      var wg sync.WaitGroup

      var allResults result

      var verbose = false

      var recursive string

      var recursiveFileList string

      var fileFilter string

      var rexfileFilter *regexp.Regexp

      var inverseSearch bool


      func init() {

      var rexError error

      flag.StringVar(&strRex, "r", "", "Regular expresion to match against the input files")

      flag.BoolVar(&verbose, "v", false, "It sets verbose output (Basically showing filename and line number for each match)")

      flag.BoolVar(&inverseSearch, "i", false, "It does what you might expect.. reverse the search")

      flag.StringVar(&recursive, "R", "", "Recursively find all files starting from the current folder and apply the given search to them")

      flag.StringVar(&fileFilter, "FF", "", "Filter to be applied to the filenames when used recursevily")

      flag.Parse()

      if strRex == "" {

      fmt.Fprintf(os.Stderr, "The '-r' (regular expression flag is mandatory)n")

      os.Exit(1)

      }

      regRex, rexError = regexp.Compile(strRex)

      if rexError != nil {

      fmt.Fprintf(os.Stderr, "Your regex '%s' cant compile. Error : %s", strRex, rexError.Error())

      os.Exit(2)

      }

      rexfileFilter, rexError = regexp.Compile(fileFilter)

      if rexError != nil {

      fmt.Fprintf(os.Stderr, "Your regex '%s' cant compile. Error : %s", rexfileFilter, rexError.Error())

      os.Exit(3)

      }

      if recursive != "" {

      var err error

      filenames, err = walkDir(recursive)

      if err != nil {

      fmt.Fprintf(os.Stderr, "%s", err.Error())

      }


      } else {


      filenames = flag.Args()

      }


      }


      func main() {


      stat, err := os.Stdin.Stat()

      if err != nil {

      fmt.Fprintf(os.Stderr, "There is an error reading from stdin : %s", err)

      os.Exit(3)

      }

      if (stat.Mode() & os.ModeNamedPipe) != 0 {

      grepStdin(os.Stdin, regRex)

      } else {

      chResults := make(chan *result, 4)

      wg.Add(len(filenames))

      for _, fn := range filenames {

      go grep(fn, regRex, &wg, chResults)

      }

      go func(wait *sync.WaitGroup, ch chan<- *result) {

      wg.Wait()

      close(ch)

      }(&wg, chResults)


      for res := range chResults {

      if verbose {

      formatRes(res, 1)

      } else {

      formatRes(res, 2)

      }


      }

      }

      }


      func grepStdin(ptr io.Reader, reg *regexp.Regexp) {

      bf := bufio.NewScanner(ptr)

      var lineno = 1


      for bf.Scan() {

      // There is no XOR in Golang, so you ahve to do this :

      if line := bf.Text(); (reg.Match(byte(line)) && !inverseSearch) || (!reg.Match(byte(line)) && inverseSearch) {


      formatRes(&result{

      Line: line,

      LineNumber: lineno,

      Error: nil,

      }, 3)

      }

      lineno++

      }

      }


      func grep(file string, reg *regexp.Regexp, wait *sync.WaitGroup, ch chan<- *result) {

      fd, err := os.Open(file)

      if err != nil {

      ch <- &result{

      Filename: file,

      Error: err,

      }

      }

      bf := bufio.NewScanner(fd)

      var lineno = 1


      for bf.Scan() {

      // There is no XOR in Golang, so you ahve to do this :

      if line := bf.Text(); (reg.Match(byte(line)) && !inverseSearch) || (!reg.Match(byte(line)) && inverseSearch) {


      ch <- &result{

      Filename: file,

      Line: line,

      LineNumber: lineno,

      Error: nil,

      }

      }

      lineno++

      }

      wg.Done()

      }


      func formatRes(r *result, format int) {

      if format == 1 {

      if r.Error == nil {

      fmt.Printf("%d - %s - %sn", r.LineNumber, r.Filename, r.Line)

      } else {

      fmt.Fprintf(os.Stderr, "%s - %s n", r.Filename, r.Error)

      }

      }

      if format == 2 {

      if r.Error == nil {

      fmt.Printf("%sn", r.Line)

      } else {

      fmt.Fprintf(os.Stderr, "%s - %s n", r.Filename, r.Error)

      }

      }

      if format == 3 {

      if r.Error == nil {

      fmt.Printf("%sn", r.Line)

      } else {

      fmt.Fprintf(os.Stderr, "%sn", r.Error)

      }

      }

      }


      func walkDir(path string) (string, error) {

      list := make(string, 0, 50)

      err := filepath.Walk(".",

      func(path string, info os.FileInfo, err error) error {

      if err != nil {

      return err

      }

      if fileFilter != "" {

      if rexfileFilter.Match(byte(filepath.Base(path))) {

      list = append(list, path)

      }

      } else {

      list = append(list, path)

      }

      return nil // Unreachable code

      })

      if err != nil {

      return nil, err

      }

      return list, nil

      }






      go concurrency






      share|improve this question







      New contributor




      Matias Barrios is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question







      New contributor




      Matias Barrios is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question






      New contributor




      Matias Barrios is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 11 mins ago









      Matias Barrios

      1062




      1062




      New contributor




      Matias Barrios is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Matias Barrios is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Matias Barrios is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.



























          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });






          Matias Barrios is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210591%2fgolang-grep-clone%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          Matias Barrios is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          Matias Barrios is a new contributor. Be nice, and check out our Code of Conduct.













          Matias Barrios is a new contributor. Be nice, and check out our Code of Conduct.












          Matias Barrios is a new contributor. Be nice, and check out our Code of Conduct.
















          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210591%2fgolang-grep-clone%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          404 Error Contact Form 7 ajax form submitting

          How to know if a Active Directory user can login interactively

          TypeError: fit_transform() missing 1 required positional argument: 'X'