Изменить диапазон строк после применения преобразований

Изменить диапазон строк после применения преобразований

Я хочу написать преобразование Киба, которое позволяет мне вставлять ту же информацию для определенного числа строк. В этом случае у меня есть файл xls, который содержит подзаголовки, и эти подзаголовки также содержат данные, например:

Client: John Doe, Code: 1234
qty, date, price
1, 12/12/2017, 300.00
6, 12/12/2017, 300.00
total: 2100
Client: Nick Leitgeb, Code: 2345
qty, date, price
1, 12/12/2017, 100.00
2, 12/12/2017, 200.00
2, 12/12/2017, 50.00
total: 600
Client: …..

Чтобы извлечь релевантные данные, я использую следующее преобразование, которое возвращает строки, которые соответствуют хотя бы одному регулярному выражению из двух предоставленных (дата или слово "клиент")

transform, SelectByRegexes regex: [/\d+\/\d+\/\d+/, /Client:/], matches: 1

Это даст мне следующий результат:

Client: John Doe, Code: 1234
1, 12/12/2017, 300.00
6, 12/12/2017, 300.00
Client: Nick Leitgeb, Code: 2345
1, 12/12/2017, 100.00
2, 12/12/2017, 200.00
2, 12/12/2017, 50.00
…..

Теперь, когда у меня есть нужная информация, мне нужно скопировать клиент и код для каждой подстроки и удалить подзаголовок.

John Doe, 1234, 1, 12/12/2017, 300.00
John Doe, 1234, 6, 12/12/2017, 300.00
Nick Leitgeb, 2345, 1, 12/12/2017, 100.00
Nick Leitgeb, 2345, 2, 12/12/2017, 200.00
Nick Leitgeb, 2345, 2, 12/12/2017, 50.00

Единственный способ, которым я могу думать, это сделать это прямо на source или в pre_process блок, но потребуются преобразования, использовавшиеся ранее для того, чтобы показать необходимые данные, возможно ли использовать класс преобразования внутри блока source/pre_process? или манипулировать несколькими строками в преобразовании?

1 ответ

Решение

Автор киба тут! Спасибо за использование Kiba. Вы правы, что вы могли бы добиться этого от специализированного source, но я лично предпочитаю использовать следующий шаблон:

last_seen_client_row = nil
logger = Logger.new(STDOUT)

transform do |row|
  # detect "Client/Code" rows - pseudo code, adjust as needed
  if row[0] =~ /\AClient:\z/
    # this is a top-level header, memorize it
    last_seen_client_row = row
    logger.info "Client boundaries detected for client XXX"
    next # remove the row from pipeline
  else
    # assuming you are working with arrays (I usually prefer Hashes though!) ; make sure to dupe the data to avoid
    last_seen_client_row.dup + row
  end
end

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

Надеюсь это поможет!

Другие вопросы по тегам