我有以下类型的文件:
1: 0.0000 2: 0.0000 3: 0.0000 4: 0.0000 5: 0.0000 6: 0.0000 7: 0.0000 8: 0.0000 9: 0.0000 10: 0.0000 11: 0.0000 12: 0.0000 13: 0.0000
14: 0.0000 15: 0.0000 16: 0.0000 17: 0.0000 18: 0.0000 19: 0.0000
20: 0.0000 21: 0.0000 22: 0.0000 23: 0.0000 24: 0.0000 25: 0.0000 26: 0.0000 27: 0.0000 28: 0.0000 29: 0.0000 30: 0.0000 31: 0.0000 32: 0.0000
33: 0.0000 34: 0.0000 35: 0.0000 36: 0.0000 37: 0.0000 38: 0.0000
文件以不同的行分隔,第二行的数字属于第一行,第四行的数字属于第三行,等等。
我需要提取0.000个数字并将其变成矩阵。
fopen
,load
,importdata
不能这样做。
请帮我解决这个问题。
答案 0 :(得分:0)
我将假设您要将每一行作为单独的1D数组加载,并将每个数组存储为cell array内的元素。如果您想将这些行存储在2D矩阵中,那么MATLAB无法为您执行此操作,因为它不支持ragged matrices。作为解决方法,您可以使用单元格数组,因为单元格数组中的内容可以是您想要的任何内容。在我们的例子中,每个元素都是不同大小的一维数组。
我建议你先做的(正如你已经尝试过的)是用fopen
打开文件。接下来,您可以使用fgetl
检索文本文件的一行,然后继续调用fgetl
,直到到达文件末尾,其中fgetl
具有{{} 1}}返回而不是文件中的有效行。请注意,如果字符串不是-1,则返回的是字符串。
检索此字符串后,解析字符串的最佳方法是使用regular expressions(通过regexp
)。正则表达式用于查找文本字符串中出现某些模式的位置。在您的情况下,我们正在寻找一个非常具体的模式。我们正在寻找以下类型的事件:
-1
您正在寻找字符串中的模式,该模式可以分为三组:
因此,我们可以使用正则表达式,以便我们可以在字符串中找到这些模式。但是,我们还需要考虑后跟[xx....xx](.)[xx....xx]
^ ^ ^
1 2 3
字符的数字,因为我刚才描述的模式可能与:
字符之前的数字相匹配。因此,我们需要在空间之间搜索整个模式。具体做法是:
:
您现在可以看到我们可以将每对唯一ID和数字分为五组:
[xx....xx]: [xx....xx](.)[xx....xx]
^ ^ ^ ^ ^
1 2 3 4 5
字符,后跟空格因此,一旦你读到你的行,你就会想要获得组#3和#5之间的值并将它们放入一个数组中。但是,这些值将是字符串,因此您需要将这些值转换为数字以创建最终的数字数组。
鉴于您从存储在:
中的文本文件中读取了一行,您将创建一个字符串数组,其中每个元素都是数字的字符串表示形式,如下所示:
s
哇!看起来很复杂吧?它实际上并不是。让我们慢慢来看看。 c = regexp(s, '\d+: (\d+\.?\d+)', 'tokens');
的第一个输入是您要检查的行,它是您文本中的一行。第二个输入是包含正则表达式模式的字符串。您可以定义正则表达式语法,该语法描述您在此字符串中查找的文本的确切模式。
因此,如果你看一下我如何将字符串分成5组,这将有助于你以直观的方式解析我创建的模式。让我们再次通过这些小组:
regexp
- 我们正在搜索至少找到一位数的事件。 \d+
表示数字,\d
表示至少查找一个或更多这些数字。+
- 我们用冒号(:
)跟着这个,然后来了一个空格接下来,我们使用所谓的capture group,我们希望专注于提取数字和冒号后面的后续内容。捕获组被:
个字符包围。
()
- 我们寻找那些至少包含一位数字的数字\d+
- 在第3组之后,我们需要通过搜索零点或一点来实现这一点。 \.?
个字符表示您要搜索零个或一个匹配项。在我们的例子中,我们想要寻找点。使用?
本身意味着wildcard,因此如果您要搜索实际的点,则需要在.
前加上。因此,我们希望寻找零点或一点。\
- 接下来,我们通过在结尾处搜索至少一位数字来实现此目的。捕获组的重要性在于,当您指定\d+
标志时,我们将在您的字符串中返回匹配的单元格数组,其中此单元格数组中的每个元素都为您提供每个捕获组的匹配项。我们定义的正则表达式语法将返回此行中包含的与上述模式匹配的每个子字符串。
因此,这里会发生的是我们将返回每个冒号之后的那些数字的单元格数组。请记住,每个字符串将被放置在1 x 1单元格数组中,所以它实际上是一个嵌套的单元格数组。因此,我们要做的是使用vertcat
解压缩这些单元格条目,然后创建一个字符串的1D单元格数组。现在,因为这些是字符串,并且您想要创建元素的数字数组,所以您需要最终使用str2double
来实现最终目标。然后,您可以将其放入单元格数组中的元素中。
换句话说,你必须这样做:
'tokens'
e = str2double(vertcat(c{:}));
将是每行文本的最终数字数组。因此,您的基本处理管道将是:
e
获得-1
fgetl
因此,你的程序非常简单。我们假设您的文字存储在名为regexp
的文件中。因此:
text.txt
%// Step #1
fid = fopen('text.txt');
%// Step #2
out = {};
%// Step #3
while true
s = fgetl(fid); %// Step #3a
if s == -1 %// Check if we need to get out - end of file
break;
end
c = regexp(s, '\d+: (\d+\.?\d+)', 'tokens'); %// Step #3b
e = str2double(vertcat(c{:})); %// Step #3c
out{end+1} = e; %// Step #3d
end
%// Step #4
fclose(fid);
将包含每行包含所有数字的输出单元格数组。鉴于上面显示的文本示例,这是我运行上述代码时得到的结果:
out
如果你比较每一行的ID数和每个冒号之后的数字,它们会匹配,即使你的例子是一堆零的假想。