Find a string in a file and delete all occurences in the file

199 views
Skip to first unread message

Vikas Kumar

unread,
Apr 22, 2017, 8:22:44 PM4/22/17
to golang-nuts
Hey All,

I am trying to iterate over an array, match the lines in a file and then delete all occurrences of the lines in the file.

See this example.

Array
var abcd = [5]string{
   
"one two",
   
"three four fix",
   
"six",
   
"seven eight nine ten",
   
"eleven twelve thirteen fourteen fifteen",
}

My File
<some text> - one two
<some text> - seven eight nine ten
<some text> - one two
<some text> - nineteen
<some text> - eleven twelve thirteen fourteen fifteen
<some text> - sixteen seventeen eighteen

Desired File
<some text> - nineteen
<some text> - sixteen seventeen eighteen

In Bash, I would have done something like this.
for i in "${abcd[@]}"
do
  sed
-i "/$i/d" <my_file>
done


PS: I am new to GoLang and trying to write a git pre-commit hook.

Thanks in advance.

Regards.

Tamás Gulácsi

unread,
Apr 23, 2017, 3:06:42 AM4/23/17
to golang-nuts
The easiest would be that sed.
Otherwise, do as sed: iterate through the lines with a bufio.Scanner, and write out libes into a bytes.Buffer iff it doesn't match.
At the end, overwrite the file with buf.Bytes using ioutil.WriteFile.

Vikas Kumar

unread,
Apr 23, 2017, 6:11:07 AM4/23/17
to golang-nuts
Thanks Tamás,

I am looking something in a Golang way so that I can create a binary and distribute it in the team which has some Windows users as well.

Thanks for the pointers. Let me try it out.

Konstantin Khomoutov

unread,
Apr 23, 2017, 9:48:11 AM4/23/17
to Vikas Kumar, golang-nuts
On Sat, 22 Apr 2017 08:08:57 -0700 (PDT)
Vikas Kumar <vika...@gmail.com> wrote:

> I am trying to iterate over an array, match the lines in a file and
> then delete all occurrences of the lines in the file.
>
> See this example.
> *Array*
> var abcd = [5]string{
> "one two",
> "three four fix",
> "six",
> "seven eight nine ten",
> "eleven twelve thirteen fourteen fifteen",
> }

You don't have to explicitly spell the length here -- should you have
used "..." instead, the compiler would have calculated the length
itself.

An even better approach in this particular case would be to use a
slice rather than an array:

var abcd = []string{"blah", ...}

> *My File*
> <some text> - one two
> <some text> - seven eight nine ten
> <some text> - one two
> <some text> - nineteen
> <some text> - eleven twelve thirteen fourteen fifteen
> <some text> - sixteen seventeen eighteen
>
> *Desired File*
> <some text> - nineteen
> <some text> - sixteen seventeen eighteen
>
> In Bash, I would have done something like this.
> for i in "${abcd[@]}"
> do
> sed -i "/$i/d" <my_file>
> done

Well, sed really does not do anything super-special: it reads the file
line-by-line and produces *another* file with the updated information.
After reading of the source file is over -- and hence producing of the
output file is over, too, -- sed would rename the new file over the old
one.

So you should do the same:

1. Use the functions from the path/filepath package to obtain the
name of the directory the source file is located in.

2. Use the io/ioutil.TempFile() to obtain a temporary file beside
the source one -- that is, in the same directory.

3. Use the bufio.Scanner type to read the source file in a linewise
manner.

4. Use the functions from the "strings" stdlib package to deal with
each line read from the source file.

If the line read matches one of your patterns, you simply move on
to reading the next line; otherwise you write in to the output file.

5. Once the input is exhausted, Flush() and Close() the output file
and then use os.Rename() to rename the output file *over* the source
file.

Be sure to check all error values returned from all the functions you
call.

Note that you'd better to actually start with a good book on Go --
I'd personally recommend to start with the "Effective Go" online paper
and then move on to "The Go Programming Language" by Donovan and
Kernigan; if you have almost no experience with compiled or C-like
languages you might consider reading first the book by Caleb Doxsey
available freely as a PDF document.

Ishan Jain

unread,
Apr 23, 2017, 10:37:37 AM4/23/17
to golang-nuts
I created a small program to demonstrate this.
As go playground doees not supports files and stuff so I put all the content of file in an array and iterated through that. You can read the file and iterate through ReadBuffer Line by line to get the same results.

Go playground link:
https://play.golang.org/p/6VmgwnsAag

Please let me know if there is something you didn't understood in my code.

Btw, I posted a reply at 1'O clock Indian Standard Time. Don't know what happened to that.
Message has been deleted

Michael Jones

unread,
Apr 23, 2017, 10:58:16 AM4/23/17
to Ishan Jain, golang-nuts
Another example:

In this case, just copy the program to your machine and build it.
i called it lines.go

when i run it as:
lines < lines.go

it echos the program with the line "six" removed

On Sun, Apr 23, 2017 at 12:47 AM, Ishan Jain <ishan...@gmail.com> wrote:
You can do it like this. I wrote the code to filter out lines from an array that does not contain words specified in array. 

package main

import (
"os"
"log"
"bufio"
"io"
"regexp"
)


var abcd = [5]string{
"one two",
"three four fix",
"six",
"seven eight nine ten",
"eleven twelve thirteen fourteen fifteen",
}

func main() {

inputFile, err := os.Open("file.txt")
if err != nil {
log.Fatalln(err)
}

reader := bufio.NewReader(inputFile)

for {
filedata, _, err := reader.ReadLine()
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
return
}

if stringsInSlice(string(filedata)) {

// Write This Line to a file.

}
}
}

func stringsInSlice(str string) bool {
for _, v := range abcd {
// \b is used to create boundary, So, It won't match a word in a bigger word.
regex, err := regexp.Compile(`\b` + v + `\b`)
if err != nil {
log.Panic("Error In Compiling Regex")
}
if len(regex.FindAllString(str, 1)) != 0 {
return true
}
}
return false
}

See this code in Action. 


If there is something in my code that you did not understood, please let me know. 

Regards

Ishan Jain

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Michael T. Jones
michae...@gmail.com

Michael Jones

unread,
Apr 23, 2017, 11:42:15 AM4/23/17
to Ishan Jain, golang-nuts
...or if you copy the strings.Contains() comparison to the test, it echoes the program with six and each of the patterns removed.  

Vikas Kumar

unread,
Apr 25, 2017, 8:20:07 AM4/25/17
to golang-nuts, ishan...@gmail.com
Thanks a ton Michael and Ishan. Let me understand the code and use this in my program.

Cheers,
Vikas

Michael Jones

unread,
Apr 25, 2017, 8:32:42 AM4/25/17
to Vikas Kumar, golang-nuts, Ishan Jain
Sure. Here's a slightly expanded example.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Vikas Kumar

unread,
Apr 28, 2017, 9:14:22 PM4/28/17
to golang-nuts, vika...@gmail.com, ishan...@gmail.com
Thanks again Michael and Ishan. My git-hook is completed now, running perfectly :)

Michael Jones

unread,
Apr 28, 2017, 9:52:32 PM4/28/17
to Vikas Kumar, golang-nuts, Ishan Jain
Great!

On Fri, Apr 28, 2017 at 6:14 PM, Vikas Kumar <vika...@gmail.com> wrote:
Thanks again Michael and Ishan. My git-hook is completed now, running perfectly :)

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages