2016-05-26 4 views
1

Я изучаю go язык и попробуйте переписать часть моего кода на Python с помощью golang. Я написал функцию генератора, которая читает текстовый файл по строкам и посылает (используя выход ключевое слово) только «правильные» строки (пустые строки игнорируются, нереализованные строки рекомпозируются).golang: читать генератор файлов

Пример файла (myfile.txt):

#123= FOOBAR(1.,'text'); 

#126= BARBAZ('poeazpfodsp', 
234,56); 

parse.py:

#!/usr/bin/python 
def validlines(filename): 
    with open(filename) as fdin: 
     buff = '' 
     for line in fdin.readlines(): 
      line = line.strip() 
      if line == '': 
       continue 
      buff += line 
      if line[-1] != ';': 
       continue 
      yield buff 
      buff = '' 
     fdin.close() 

for line in validlines('myfile.txt'): 
    print(line) 

дисплеи:

#123= FOOBAR(1.,'text'); 
#126= BARBAZ('poeazpfodsp',234,56);  

Теперь я пытаюсь сделать это таким же образом, используя закрытие в голанге:

pa rse.go:

package main 

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

func validLines(filename string) (func() (string, bool)) { 

    file, _ := os.Open(filename) 
    scanner := bufio.NewScanner(file) 

    return func() (string, bool) { 
     buff := "" 
     for scanner.Scan() { 
      line := scanner.Text() 
      line = strings.TrimSpace(line) 

      if line == "" { 
       continue 
      } 
      buff += line 
      if line[len(line)-1] != ';' { 
       continue 
      } 
      return buff, true 
     } 

     file.Close() 
     return "", false 
    } 
} 

func main() { 
    vline := validLines("myfile.txt") 
    for line, ok := vline(); ok; { 
     fmt.Println(line) 
    } 
} 

дисплеи:

#123= FOOBAR(1.,'text'); 
#123= FOOBAR(1.,'text'); 
#123= FOOBAR(1.,'text'); 
#123= FOOBAR(1.,'text'); 
#123= FOOBAR(1.,'text'); 
#123= FOOBAR(1.,'text'); 
#123= FOOBAR(1.,'text'); 
... 

Что такое правильный способ сделать это в golang?

ответ

1

Это цикл for вашего основного источника, который является проблемой. С помощью этого синтаксиса, вот что он делает:

  1. Initialize line и ok с первым вызовом vline()
  2. Если ok верно, запустите цикл один раз
  3. Update-то в конце блока, и перейти к 2.

Итак, ваша проблема в том, что вы никогда не обновляете line и ok. Вот правильная версия:

for line, ok := vline(); ok; line, ok = vline() { ... } 
+0

Я искал проблему в функции validLines, спасибо большое. –

1

небольшое изменение:

func main() { 
    vline := validLines("myfile.txt") 
    line, ok := vline() 
    for ok { 
     fmt.Println(line) 
     line, ok = vline() 
    } 
} 
6

В Go вы можете использовать каналы вместо выхода, это очень удобно.

пакет главного

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

func ValidLines(filename string) (c chan string) { 
    c = make(chan string) 
    buff := "" 
    go func() { 
     file, err := os.Open(filename) 
     if err != nil { 
      close(c) 
      return 
     } 

     reader := bufio.NewReader(file) 
     for { 
      line, err := reader.ReadString('\n') 
      if err != nil { 
       close(c) 
       return 
      } 
      line = strings.TrimSpace(line) 
      if line == "" { 
       continue 
      } 
      buff += line 
      if line[len(line)-1] != ';' { 
       continue 
      } 
      c <- buff 
      buff = "" 
     } 
    }() 
    return c 
} 

func main() { 
    for line := range ValidLines("myfile.txt") { 
     fmt.Println(line) 
    } 
} 
+1

Я бы предложил 'defer закрыть (c)' в верхней части вашей анонимной функции. – Jeff

2

Просто немного дополнения к pav5000's answer, вы должны сделать канал буферизованным:
C: = сделать (чан строка, 1)
В противном случае, он будет читает весь файл в канал, и нет смысла его использовать.

Смежные вопросы