2015-12-23 2 views
0

У меня есть текстовый файл с многострочными строками, ограниченный пустой строкой. Какой был бы лучший способ прочитать эту строку для строки в Go?Golang: Чтение текстового файла с многострочными строками

Я думаю, что мне, возможно, придется использовать сканер с моей собственной функцией Split, но просто интересно, есть ли лучший/более простой способ, который мне не хватает.

Я попытался с помощью моего собственного Splitfunc на основе bufio.ScanLines:

func MyScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) { 
    if atEOF && len(data) == 0 { 
      return 0, nil, nil 
    } 
    if i := bytes.IndexAny(data, "\n\n"); i >= 0 { 
      return i + 1, dropCR(data[0:i]), nil 
    } 
    if atEOF { 
      return len(data), dropCR(data), nil 
    } 
    return 0, nil, nil 
} 

Но я получаю ошибку на вызове IndexAny: «ошибка синтаксиса: неожиданную точку с запятой или символ новой строки, ожидая)» - Исправлено

Обновление: Исправлена ​​ошибка синтаксиса выше, как предлагается, но я получаю только первую строку. Я читаю файл следующим образом:

scanner.Split(MyScanLines) 
scanner.Scan() 
fmt.Println(scanner.Text()) 

Любые предложения?

Пример тестового файла Я пытаюсь читать:

Name = "John" 
Surname = "Smith" 
Val1 = 700 
Val2 = 800 

Name = "Pete" 
Surname = "Jones" 
Val1 = 555 
Val2 = 666 
Val3 = 444 

. 
. 
. 
+0

Просьба представить образец файла, который вы пытаетесь читать. –

+0

@PrashantThakkar Пример представлен в исходном сообщении сейчас. Некоторые пары значений могут быть в одной записи, а не в других, и порядок также не фиксируется. – Kosie

+0

Спасибо, за ошибку, которую вы получаете, четко сказано, что «)» отсутствует. Исправлено: если i: = bytes.IndexAny (данные, "\ n \ n"); i> = 0 { –

ответ

1

Разразившийся. Сначала поймите, сканирование и убедитесь, что работает:

package main 

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

func main() { 
    scanner := bufio.NewScanner(strings.NewReader(data)) 
    for scanner.Scan() { 
     l := scanner.Text() 
     fmt.Println(l) 

    } 

} 

var data = ` 
Name = "John" 
Surname = "Smith" 
Val1 = 700 
Val2 = 800 

Name = "Pete" 
Surname = "Jones" 
Val1 = 555 
Val2 = 666 
Val3 = 444 
` 

Вот the code on the Go playground.

Затем, соберите нужные данные в кусочек. Вероятно, есть способ проверить конец файла, EOF, но я не смог его найти. Это то, что я придумал, и это работает:

package main 

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

func main() { 
    buffer := [][]string{} 
    block := []string{} 
    scanner := bufio.NewScanner(strings.NewReader(data)) 
    for scanner.Scan() { 
     l := scanner.Text() 

     if len(l) != 0 { 
      block = append(block, l) 
      continue 
     } 

     if len(l) == 0 && len(block) != 0 { 
      buffer = append(buffer, block) 
      block = []string{} 
      continue 
     } 

     if len(l) == 0 { 
      block = []string{} 
      continue 
     } 

    } 

    if len(block) != 0 { 
     buffer = append(buffer, block) 
     block = []string{} 
    } 

    fmt.Println("PRINTING BUFFER - END OF PROGRAM - ALL DATA PROCESSED:", buffer) 

} 

var data = ` 
Name = "John" 
Surname = "Smith" 
Val1 = 700 
Val2 = 800 

Name = "Pete" 
Surname = "Jones" 
Val1 = 555 
Val2 = 666 
Val3 = 444 
` 

Вот the code on the playground.

+0

Большое спасибо за это! – Kosie

+0

Вы в основном приняли мой ответ и отправили его обратно ... вы даже не изменили имена переменных, чтобы имитировать решение проблемы самостоятельно. Pitiful ... – Elwinar

+0

Целью является решение, а не права ИС или гениальная оригинальность. Ваш код не работал. Я предложил еще одну итерацию. Я указал, где я чувствую, что мой код может быть улучшен. Кто-то улучшил его, предоставив еще одну итерацию. Работа в команде была сосредоточена на решении. Для меня, вот что такое stackoverflow: кодеры собираются вместе, чтобы помогать друг другу. Я не пытаюсь украсть ваш код. Остынь и играй хорошо. Вызов имени невозможен. –

2

Вы способ работает, но я бы посоветовал вам использовать bufio.Scanner, который по умолчанию линии сканирования по линии. Затем вы просто начинаете читать свой файл по строкам и заполняете свою структуру. Когда вы сталкиваетесь с пустой строкой, поместите вашу структуру в срез и начните с новой.

Вот пример, взятый из одного из моих проектов с открытым исходным кодом, которые демонстрируют его:

buffer := [][]string{} 
block := []string{} 
scanner := bufio.NewScanner(strings.NewReader(data)) 
for scanner.Scan() { 
    l := scanner.Text() 

    if len(strings.TrimSpace(l)) != 0 { 
     block = append(block, l) 
     continue 
    } 

    // At this point, the script has reached an empty line, 
    // which means the block is ready to be processed. 
    // If the block is not empty, append it to the buffer and empty it. 
    if len(block) != 0 { 
     buffer = append(buffer, block) 
     block = []string{} 
    } 
} 

if len(block) != 0 { 
    buffer = append(buffer, block) 
} 
+0

Ваш код не работает. Посмотрите здесь, на игровой площадке Go: https://play.golang.org/p/v5aOCK7zRG –

+0

Спасибо, что упомянули об этом, я фактически перевернул условие, удалив ненужный контекст из моего кода. Я исправил его и добавил в конце проверку, чтобы указать конец файла. – Elwinar

+0

Вы можете видеть, как это работает здесь: https://play.golang.org/p/icydx1kKu7 – Elwinar

1

bufio.Scan() возвращает false на EOF. Мы вернем второй аргумент «ok», поэтому наш вызывающий абонент может узнать, есть ли у нас в конце нашего ввода.

Лучше всего накапливать нашу запись во фрагменте строк и конкатенировать в конце. Очевидный способ добавления каждой строки в свою очередь к строке результатов будет работать, но это O (n^2) в количестве строк.

Собираем все вместе:

func ReadBlock(scanner *bufio.Scanner) (string, bool) { 
    var o []string 
    if scanner.Scan() == false { 
     return "", false 
    } 

    for len(scanner.Text()) > 0 { 
     o = append(o, scanner.Text()) 
     if scanner.Scan() == false { 
      break 
     } 
    } 
    return strings.Join(o, " "), true 
} 

https://play.golang.org/p/C_fB8iaYJo

P.S. глядя на ваш вход, я подозреваю, что вы захотите вернуть результат как карту, а не конкатенированную строку.

2

Вот альтернативный подход, чтобы сделать то же самое, используя bufio.Reader. Логика почти схожа с ответом Elwiner.

myReadLine Функция ниже использует bufio.Reader, чтобы прочитать следующую многострочную запись в файле.

func myReadLine(file *os.File, reader *bufio.Reader) (lines []string, err error){ 
    for { 
    line, _, err := reader.ReadLine() 
    if err != nil || len(line) == 0 { 
     break 
    } 
    lines = append(lines, string(line)) 
    } 
    return lines, err 
} 

Ниже пример кода иллюстрирует пример использования вышеуказанной функции:

reader := bufio.NewReader(file) 
for { 
    lines, err := myReadLine(file, reader) 
    if err != nil || len(lines) == 0 { 
     break 
    } 
    fmt.Println(lines) 
} 
Смежные вопросы