我用matlab创建了 .txt 文件,这些文件有不同的3列,用制表符分隔(字符串,浮点数,浮点数)和不同的行数。
我试图将这3列数据中的每一行都读成3个不同的变量。这是我的代码:
fileId = fopen('file.txt');
% Storing columns from txt file into appropriate compartment data arrays
compartment_name = textscan(fileId,'%s%*f%*f','Delimiter','\t'); % column of strings
compartment_length = textscan(fileId,'%*s%f%*f','Delimiter','\t'); % column of doubles
compartment_diameter = textscan(fileId,'%*s%*f%f','Delimiter','\t'); % column of doubles
fclose('file.txt');
我收到 compartment_name 的正确数据(包含106x1单元格的1x1单元格(每个单元格都是一个字符串)),但是 compartment_length 和 compartment_diameter 返回一个空的1x1单元格,其中包含 0x1 double。
有什么想法吗?
- 有什么简单的方法可以将1x1单元转换为数组吗?即对于compartment_name,它将是一个1x106字符串的数组?
答案 0 :(得分:1)
正如@jgrant所说in a comment,问题是如果你想重新阅读文件的部分内容,你必须将文件位置指示器重置到文件的开头。
我无法理解您为什么要尝试三次textscan
,textscan
的输出是一个单元格的原因正是您可以单独执行调用它,然后分开输出列:
tmpcell = textscan(fileId,'%s%f%f','Delimiter','\t'); % column of strings
compartment_name = tmpcell{1};
compartment_length = tmpcell{2};
compartment_diameter = tmpcell{3};
% or if you want to be fancy about it:
%[compartment_name, compartment_length, compartment_diameter] = tmpcell{:};
我写这个答案的原因是你的最后一点:
另外 - 有什么简单的方法可以将1x1单元格转换为数组吗?即对于compartment_name,它将是一个1x106字符串的数组?
这暗示了你在MATLAB中对字符串的困惑。在MATLAB中,字符串本质上是整数数组。您可以通过对字符串执行任何类型的算术运算来自行查看:
>> tmpstring = 'asdf'
tmpstring =
asdf
>> tmpstring*1
ans =
97 115 100 102
您看到的数字是字符串中字符的ASCII表示形式。这也是相反的方法:您可以通过将整数放入数组来构建字符串。事实上,对于所有意图和目的,字符串是整数数组:
>> isequal([97 115 100 102],'asdf')
ans =
1
这也暗示了MATLAB中字符串的一些限制。你的问题是什么,你不能简单地创建一个字符串数组。这恰好是字符串连接:如果string1
和string2
都只是整数数组,那么[string1, string2]
就是两个字符串的串联。
然后,您可以考虑使用[string1; string2]
水平堆叠字符串。现在,这与两个整数数组的工作方式完全相同:如果字符串长度相等,则只能执行此操作(按长度我现在表示size(string1,2)
)。因此,在一般情况下,您只能将字符串存储在非均匀容器中,即MATLAB中的单元格。一旦你有了单元格,你的元素可以有任何类型和形状,所以你可以轻松地将任意长度的字符串一起推,垂直或水平堆叠,无论你喜欢它们。
所以考虑一下textscan
。您需要实现此函数,该函数将返回从文件读取的数据。数据可以是数字或字符串。你是做什么?正是textscan
正在做什么:将数字列作为数组返回(因为每一行都有一个标量数据),并将字符串作为单元格返回(因为每行包含一个字符串,即一个向量本身!)。你可以水平地堆叠字符串,但这仅在给定列中的每一行包含相同数量的字符时才有效,这显然不应该被假设,也不应该被规定。您可以仍然将字符串填充到最长元素并返回堆叠字符数组,但这会在大多数实际应用程序中引入不必要的开销。 (旁注:textscan
返回一个单元格行向量作为其输出,每个单元格元素包含给定列中的完整数据。对于数字列,这个"完整数据"是一个数组列向量,对于字符串列,它是一个单元格列向量。)
textscan
将其字符串列作为单元格返回是合理的。如果您愿意,您自己仍然可以将字符串堆叠成2d字符串数组,但在大多数情况下,这并不是真正实用的。这实际上取决于你的申请。
一个最小的例子:考虑tmp.inp
包含
asf 3 4
asdg 2 3
asd 1 4
现在
>> fid=fopen('tmp.inp','r'); outcell=textscan(fid,'%s%f%f'), fclose(fid);
outcell =
{3x1 cell} [3x1 double] [3x1 double]
这表明outcell
的输出是一个单元行向量,每个元素对应一个从文件读入的列。第2列和第3列周围的方括号表示那些单元格元素(即outcell{2}
和outcell{3}
,不要与outcell(2)
和outcell(3)
混淆)是数字数组。但是,第一个元素是单元格列向量:
>> outcell{1}
ans =
'asf'
'asdg'
'asd'
输出在每一行打印带引号的事实表明这些是单元格中包含的单独字符串,但您也可以通过
来判断>> whos ans
Name Size Bytes Class Attributes
ans 3x1 356 cell
现在,正如我所说,你可以决定将列叠加在一起,你只需要在你的单元格上调用char()
:
>> char(outcell{1})
ans =
asf
asdg
asd
>> whos ans
Name Size Bytes Class Attributes
ans 3x4 24 char
请注意自动输出中缺少引号,以及输出本身的类/大小。通过将所有行填充到最长字符串的大小(即4)来实现3x4
大小。因此,输出的第一行和第三行以空格结束(这就是我们所说的字符串的意思< EM>填充)。
如果您没有执行此填充,您可以简单地将读入的字符串作为单元格元素引用:
>> outcell{1}{3}
ans =
asd
或者,通过按原样存储变量:
>> compartment_name=outcell{1}
compartment_name =
'asf'
'asdg'
'asd'
>> compartment_name{3}
ans =
asd