MATLAB - 从字符串元胞数组中提取数字

MATLAB - Extracting numbers from a cell array of strings

我想从文本文件中提取数字。 首先,我读取文件并将其导入为以下形式的元胞数组:

A = {
        '1   0   0   0   -   0:  0.000741764'
        '2   0   0   0   -   0:          100'
        '3   0   0   0   -   0:          100'
        '4   0   0   0   -   0:          100'
        '5   0   0   0   -   0:   0.00124598'
        '6   0   0   0   -   0:  0.000612725'
        '7   0   0   0   -   0:  0.000188365'
        '8   0   0   0   -   0:            0'
        '9   0   0   0   -   0:            0'
        '10   0   0   0   -   0:            0'
        '11   0   0   0   -   0:            0'
        '12   0   0   0   -   0:            0'};

我需要根据左边整数的值得到右边的数字。 例如我需要知道对应于 3 和 6 的值(100 和 0.000612725):

'3   0   0   0   -   0:          100'
'6   0   0   0   -   0:  0.000612725'

这是我的代码:

clear all
close all
clc

A = {
        '1   0   0   0   -   0:  0.000741764'
        '2   0   0   0   -   0:          100'
        '3   0   0   0   -   0:          100'
        '4   0   0   0   -   0:          100'
        '5   0   0   0   -   0:   0.00124598'
        '6   0   0   0   -   0:  0.000612725'
        '7   0   0   0   -   0:  0.000188365'
        '8   0   0   0   -   0:            0'
        '9   0   0   0   -   0:            0'
        '10   0   0   0   -   0:            0'
        '11   0   0   0   -   0:            0'
        '12   0   0   0   -   0:            0'};

THREE = 3;
SIX = 6;

M  = cellfun(@str2num, A, 'UniformOutput', false);
Values = cell2mat(M);

Index_3 = find(Values(:,1) == SIX);
Index_6 = find(Values(:,1) == SIX);

sp_3 = strsplit(A{Index_3},':');
sp_6 = strsplit(A{Index_6},':');

VALUE_3 = str2double(sp_3(end));
VALUE_6 = str2double(sp_6(end));

但是我得到一个错误:

Error using cat
Dimensions of matrices being concatenated are not consistent.
Error in cell2mat (line 84)
            m{n} = cat(1,c{:,n});
Error in test (line 23)
Values = cell2mat(M); 

,因为:

M = 
    [1x4   double]
    [1x104 double]
    [1x104 double]
    [1x104 double]
    [1x4   double]
    [1x4   double]
    [1x4   double]
    [1x4   double]
    [1x4   double]
    [1x4   double]
    [1x4   double]
    [1x4   double]

我试过了:

str2double

相反,我得到的是 M 中所有值的 NaN。

这是使用 regular expressions 的完美案例。正则表达式是在文本中寻找模式的强大工具。在您的情况下,您首先要查找的是字符串开头的数字。接下来,您要在字符串末尾找到相应的数字。您还在评论中提到,您可能会得到指数表示法的数字(类似于 2.50652e-007)。这也很容易处理,我将把它作为另一个条目添加到您的元胞数组中以证明它有效。

我将如何处理整个元胞数组。我这样做是因为我确定您需要查看其他数字,而不仅仅是第三个和第六个条目,所以如果我们先这样做,那么您将很容易获得所需的其他内容。

我们可以在两个正则表达式调用中提取开始值和结束值 regexp 来提取开始值和结束值,如下所示:

%// Your code to define A and also new entry with exponential notation
A = {
        '1   0   0   0   -   0:  0.000741764'
        '2   0   0   0   -   0:          100'
        '3   0   0   0   -   0:          100'
        '4   0   0   0   -   0:          100'
        '5   0   0   0   -   0:   0.00124598'
        '6   0   0   0   -   0:  0.000612725'
        '7   0   0   0   -   0:  0.000188365'
        '8   0   0   0   -   0:            0'
        '9   0   0   0   -   0:            0'
        '10   0   0   0   -   0:            0'
        '11   0   0   0   -   0:            0'
        '12   0   0   0   -   0:            0',
        '13   0   0   0   -   0: 2.50652e-007'};

%// Begin new code
beginStr = regexp(A, '^\d+', 'match');
endStr = regexp(A, '(\d*\.?\d+(e-\d+)?)$', 'match');

看起来有点复杂,但是很容易解释。 regexp 默认接受两个参数:字符串或字符串元胞数组(例如您的情况)和要搜索的模式。我还选择了标志 'match' 因为我想要返回实际的字符串。默认情况下,regexp returns 索引 发生匹配的位置。

第一个 regexp 调用查找出现在 字符串开头 的数字序列。 \d+ 表示查找一个或多个数字,^ 表示查找 字符串的开头 ,因此将这两者结合起来表示您是在字符串的开头寻找数字序列。我假设字符串的开头是一个整数,所以我们可以摆脱这个。将返回的是一个元胞数组,其中每个条目都是 另一个 匹配元胞数组。如果这可行,我们应该得到一个元胞数组,其中包含一堆 1 x 1 元胞,每个元胞都是开头的数字。

第二个 regexp 调用查找一个数字序列,其中可选地有一组数字 (\d*),后跟一个可选的小数点 (\.?),后跟至少 1 个数字 (\d+) 然后 可选 我们寻找 e 字符、- 字符和另一串数字点(\d+)。请注意,这些都是通过 (e-\d+)? 组合在一起的,这意味着这个指数级的东西是可选的。此外,整个模式都出现在字符串的 end 处,因此括号将所有这些标记组合在一起并以 $ 结尾,这意味着查看 字符串结尾* 字符表示查找零次或多次出现,? 字符表示查找零次或一次出现。同样为了保持一致,+ 字符表示查找一次或多次出现。

请注意,正则表达式中的 . 字符表示通配符或任何字符。如果明确要匹配小数点,需要在.字符前加一个\。因此,正则表达式是在字符串末尾找到模式,其中我们可以选择在可选的小数点之前有一堆数字,然后在这两个可选的东西后面至少有一个数字。这将类似于第一个 regexp 调用的输出,但数字位于字符串的末尾。

让我们用celldisp仔细检查一下:

>> format compact
>> celldisp(beginStr)
beginStr{1}{1} =
1
beginStr{2}{1} =
2
beginStr{3}{1} =
3
beginStr{4}{1} =
4
beginStr{5}{1} =
5
beginStr{6}{1} =
6
beginStr{7}{1} =
7
beginStr{8}{1} =
8
beginStr{9}{1} =
9
beginStr{10}{1} =
10
beginStr{11}{1} =
11
beginStr{12}{1} =
12
beginStr{13}{1} =
13
>> celldisp(endStr)
endStr{1}{1} =
0.000741764
endStr{2}{1} =
100
endStr{3}{1} =
100
endStr{4}{1} =
100
endStr{5}{1} =
0.00124598
endStr{6}{1} =
0.000612725
endStr{7}{1} =
0.000188365
endStr{8}{1} =
0
endStr{9}{1} =
0
endStr{10}{1} =
0
endStr{11}{1} =
0
endStr{12}{1} =
0
endStr{13}{1} =
2.50652e-007

我觉得不错!现在您的最后一项任务是将数字转换为双精度数。我们可以像您为我们所做的那样使用 cellfun 调用:

beginNumbers = cellfun(@(x) str2double(x{1}), beginStr);
endNumbers = cellfun(@(x) str2double(x{1}), endStr);

beginNumbersendNumbers 将包含我们转换后的数字。让我们将它们放入一个矩阵中并显示它的样子:

out = [beginNumbers endNumbers];
format long g;

我使用format long g来显示尽可能多的有效数字。这就是我们得到的:

>> out

out =

                         1               0.000741764
                         2                       100
                         3                       100
                         4                       100
                         5                0.00124598
                         6               0.000612725
                         7               0.000188365
                         8                         0
                         9                         0
                        10                         0
                        11                         0
                        12                         0
                        13               2.50652e-07

酷!现在如果你想要第三个和第六个数字,就这样做:

>> third = out(3,:)

third =

     3   100

>> sixth = out(6,:)

sixth =

                         6               0.000612725

以上为您获取整行,但如果您特别想要与 ID 对应的相应数字,只需执行以下操作:

>> third = out(3,2)

third =

   100

>> sixth = out(6,2)

sixth =

               0.000612725