【问题标题】:Loading text file as a 2D array of strings without specifying the number of columns将文本文件加载为二维字符串数组而不指定列数
【发布时间】:2018-07-05 21:38:43
【问题描述】:

假设我有一个明文文件test.dat:

foo bar baz
qux ham spam

我知道想将其作为二维元胞数组加载到 Octave(或 Matlab 中),保留以空格和换行符编码的结构。根据我对the documentation的理解,应该是这样的:

format = '%s';
file = fopen('test.dat');
data = textscan(file,format);
fclose(file);
disp(data);

但是这只会将数据加载为一维数组:

{
  [1,1] = 
  {
    [1,1] = foo
    [2,1] = bar
    [3,1] = baz
    [4,1] = qux
    [5,1] = ham
    [6,1] = spam
  }
}

明确指定DelimiterWhitespaceEndOfLine 没有帮助(那么后者的意义何在?);也不使用其他加载函数,如 textreaddlmread。有效的是在上面使用format = '%s%s%s',但这需要我以某种方式确定列数,函数应该能够自己完成。

因此我问:是否有任何内置函数可以满足我的需求?我对自己编写这样一个函数的方法不感兴趣——我有信心我可以做到这一点,但这正是我想要避免的(因为我需要用它来展示良好的做法,因此不要重新发明轮子)。

相关问答(所有都知道列数):

【问题讨论】:

  • 如果您使用%s 作为格式,textscan 会将整行视为一个字符串,所以是的,您确实需要知道列数。您唯一的其他选择是使用fgetl 一次扫描每一行,然后使用您必须将每行拆分为单独字符串的任何分隔符解析结果行。
  • @am304:如果您使用%s 作为格式,textscan 会将整行视为一个字符串 – 不,它不会。它单独加载六个元素中的每一个;只是安排丢失了。

标签: matlab csv file-io octave


【解决方案1】:

您可以使用readtable

data = readtable('test.txt', 'ReadVariableNames', false, 'Delimiter', ' ')

输出:

Var1     Var2      Var3 
_____    _____    ______

'foo'    'bar'    'baz' 
'qux'    'ham'    'spam'

如果你想要一个单元格,而不是一个表格,你可以使用

data = table2cell( data );

>> data = {'foo'    'bar'    'baz' 
           'qux'    'ham'    'spam'}

我不确定 readtable 是 Octave 方法,它似乎是 on GitHub 但我没有要检查的安装。它于 2013b 年被引入 Matlab。


您可以使用较低级别的操作,逐行阅读

fid = fopen('test.txt','r');
data = {};
while ~feof(fid)
    line = fgets(fid);       % Read line
    A = strsplit(line, ' '); % Split on spaces
    data(end+1, :) = A;      % Append to output
end
fclose(fid);

>> data = {'foo'    'bar'    'baz' 
           'qux'    'ham'    'spam'}

此方法假定data 的每一行将具有相同数量的元素(每行中的分隔符数量相同)。如果您不能这样假设,那么更安全的方法是使用data{end+1,1} = A,然后再拆分行。

此方法中使用的唯一不是低级文件 I/O 的函数是strsplit。这是OctaveMatlab 的内置函数。

【讨论】:

    【解决方案2】:

    在 Octave 中,您可以使用 io 包中的 csv2cell

    pkg load io
    result = csv2cell('test.dat',' ')
    

    【讨论】:

      【解决方案3】:

      我建议你看看 fgetl() 或 fgets() 函数。 基本上,您阅读文件的行,然后您可以使用 textscan() 应用您的代码并获取“列”。

      【讨论】:

      • 这并没有解决我的问题,该问题明确表示我自己没有实现这一点。 @Wolfie:这也不是一个有效的评论(它对 cme​​ts 没有任何作用)。
      • @Wrzlprmft 你说得对,我已经按计划删除了评论,只是想帮助 Ari 了解网站的运作方式。我还更新了我的答案以使用 Octave 内置方法
      【解决方案4】:

      我遇到了同样的问题。在 Matlab 中 readtable.m 对我来说很慢,并且 fgetl 示例正在循环调整大小。 但也许一个可以接受的解决方案是基于这个论坛帖子: https://de.mathworks.com/matlabcentral/answers/476483-how-to-use-textscan-on-a-cell-array-without-a-loop

      所以,至少在较新的 Matlab 中:

      fid=fopen(file,'r');
      data=textscan(fid,'%s','Delimiter','\r\n');
      fclose(fid);
      data=split(data{1},';',1); 
      

      我还没有测试 split.m 处理大数据的速度。

      【讨论】:

      • 抱歉,我忘记添加元胞数组转置以将数据恢复为列/行形状。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-08
      • 2019-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多