如何将 csv 文件读入 SWI prolog 中的列表列表,其中内部列表代表 CSV 的每一行?

Udo*_*ike 6 csv io prolog swi-prolog dcg

我有一个类似于下面的 CSV 文件:即不是 Prolog 格式

james,facebook,intel,samsung
rebecca,intel,samsung,facebook
Ian,samsung,facebook,intel
Run Code Online (Sandbox Code Playgroud)

我正在尝试编写一个 Prolog 谓词来读取文件并返回一个看起来像的列表

[[james,facebook,intel,samsung],[rebecca,intel,samsung,facebook],[Ian,samsung,facebook,intel]]
Run Code Online (Sandbox Code Playgroud)

在其他谓词中进一步使用。

我仍然是一个初学者,并从 SO 中找到了一些很好的信息并对其进行了修改以查看我是否可以得到它,但我被卡住了,因为我只生成了一个看起来像这样的列表

[[(james,facebook,intel,samsung)],[(rebecca,intel,samsung,facebook)],[(Ian,samsung,facebook,intel)]]
Run Code Online (Sandbox Code Playgroud)

这意味着当我调用内部列表的头部时,我得到(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) 
    ).
Run Code Online (Sandbox Code Playgroud)
main(Lines) :- 
    open('file.txt', read, Input), 
    stream_representations(Input, Lines), 
    close(Input).
Run Code Online (Sandbox Code Playgroud)

Dav*_*fer 1

问题出在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|...].
Run Code Online (Sandbox Code Playgroud)

然后我们重新组合读入的原始原子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'.
Run Code Online (Sandbox Code Playgroud)

我们尝试将这个原子映射到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).
Run Code Online (Sandbox Code Playgroud)

您在这里看到了问题: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).
Run Code Online (Sandbox Code Playgroud)

因此,该','(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.
Run Code Online (Sandbox Code Playgroud)

但这是相当野蛮的。

我们必须用更少的步骤完成整个处理:

  1. 读取输入中的一行以逗号分隔的字符串。
  2. 直接将其转换为原子列表或字符串列表。

DCG 似乎是正确的解决方案。也许有人可以添加两行。