Как прочитать файл CSV в список списков в прологе SWI, где внутренний список представляет каждую строку CSV? - PullRequest
2 голосов
/ 20 марта 2020

У меня есть CSV-файл, который выглядит примерно так: т.е. не в формате Prolog

james,facebook,intel,samsung
rebecca,intel,samsung,facebook
Ian,samsung,facebook,intel

Я пытаюсь написать предикат Prolog, который читает файл и возвращает список, который выглядит как

[[james,facebook,intel,samsung],[rebecca,intel,samsung,facebook],[Ian,samsung,facebook,intel]]

для дальнейшего использования в других предикатах.

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

[[(james,facebook,intel,samsung)],[(rebecca,intel,samsung,facebook)],[(Ian,samsung,facebook,intel)]]

, что означает, что когда я вызываю заголовок внутренних списков, я получаю (james,facebook,intel,samsung), а не james.

Вот код используется :- (замечено на SO и изменено)

stream_representations(Input,Lines) :-
    read_line_to_codes(Input,Line),
    (   Line == end_of_file 
    ->  Lines = []
    ;   atom_codes(FinalLine, Line), 
        term_to_atom(LineTerm,FinalLine), 
        Lines = [[LineTerm] | FurtherLines],
        stream_representations(Input,FurtherLines) 
    ).
main(Lines) :- 
    open('file.txt', read, Input), 
    stream_representations(Input, Lines), 
    close(Input).

1 Ответ

1 голос
/ 20 марта 2020

Проблема заключается в term_to_atom(LineTerm,FinalLine).

Сначала мы читаем строку файла CSV в список кодов символов в read_line_to_codes(Input,Line).

Давайте смоделируйте ввод с помощью atom_codes/2:

?- atom_codes('james,facebook,intel,samsung',Line).
Line = [106, 97, 109, 101, 115, 44, 102, 97, 99|...].

Затем мы рекомбинируем исходный атом, считанный в FinalLine (это кажется расточительным, должен быть способ навести строку в непосредственно атом)

?- atom_codes('james,facebook,intel,samsung',Line), 
   atom_codes(FinalLine, Line). 

Line = [106, 97, 109, 101, 115, 44, 102, 97, 99|...],
FinalLine = 'james,facebook,intel,samsung'.

Мы пытаемся отобразить этот атом в FinalLine в термин LineTerm, используя term_to_atom/2

?- atom_codes('james,facebook,intel,samsung',Line), 
   atom_codes(FinalLine, Line),
   term_to_atom(LineTerm,FinalLine).

Line = [106, 97, 109, 101, 115, 44, 102, 97, 99|...],
FinalLine = 'james,facebook,intel,samsung',
LineTerm =  (james, facebook, intel, samsung).

Здесь вы видите проблему: LineTerm это не совсем список, а вложенный термин, использующий функтор , для разделения элементов:

?- atom_codes('james,facebook,intel,samsung',Line), 
   atom_codes(FinalLine, Line),
   term_to_atom(LineTerm,FinalLine),
   write_canonical(LineTerm).

','(james,','(facebook,','(intel,samsung)))

Line = [106, 97, 109, 101, 115, 44, 102, 97, 99|...],
FinalLine = 'james,facebook,intel,samsung',
LineTerm =  (james, facebook, intel, samsung).

Этот термин ','(james,','(facebook,','(intel,samsung))) также будет в окончательный результат, просто пишется по-другому: (james,facebook,intel,samsung) и упакован в список: [(james,facebook,intel,samsung)]

Вы не хотите этот термин, вы хотите список. Вы можете использовать atomic_list_concat/2 для создания нового атома, который можно прочитать как список:

?- atom_codes('james,facebook,intel,samsung',Line), 
   atom_codes(FinalLine, Line),
   atomic_list_concat(['[',FinalLine,']'],ListyAtom),
   term_to_atom(LineTerm,ListyAtom),
   LineTerm = [V1,V2,V3,V4].

Line = [106, 97, 109, 101, 115, 44, 102, 97, 99|...],
FinalLine = 'james,facebook,intel,samsung',
ListyAtom = '[james,facebook,intel,samsung]',
LineTerm = [james, facebook, intel, samsung],
V1 = james,
V2 = facebook,
V3 = intel,
V4 = samsung.

Но это скорее варвар c.

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

  1. Считайте строку разделенных запятыми строк на входе.
  2. Преобразуйте это в список атомов или строк напрямую.

DCG кажутся правильным решением. Может быть, кто-то может добавить двухслойный.

...