【问题标题】:MATLAB - Extracting numbers from a cell array of stringsMATLAB - 从字符串元胞数组中提取数字
【发布时间】:2015-08-15 00:15:34
【问题描述】:

我想从文本文件中提取一个数字。 首先我读取文件并导入为以下形式的单元格数组:

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。

【问题讨论】:

    标签: string matlab numbers cell


    【解决方案1】:

    这是使用regular expressions 的完美案例。正则表达式是在文本中寻找模式的强大工具。在您的情况下,您首先要查找的是字符串开头的数字。接下来,您要在字符串末尾找到相应的数字。您还在您的 cmets 中提到您可能会以指数表示法获得数字(类似于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 返回匹配发生位置的索引

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

    第二个regexp 调用查找一个数字序列,这样可以有一组数字(\d*),后跟一个可选的小数点(\.?),后跟至少一个数字(@ 987654335@) 然后可选地我们寻找e 字符、- 字符和在此点之后的另一串数字(\d+)。请注意,这些都是通过(e-\d+)? 组合在一起的,这意味着这个指数的东西是可选的。此外,整个模式都出现在字符串的 end 处,因此括号将所有这些标记组合在一起并以 $ 结尾,这意味着查看字符串的 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
    

    【讨论】:

    • 我不会在我所有的答案中添加这么多信息 :D 解释得很好! +1
    • @rayryeng 一如既往的精彩!谢谢!
    • @SanthanSalai - 谢谢 :) 正则表达式我觉得他们总是需要很多解释。这是一种很多人不太了解的黑魔法(包括我!),所以使用它们的问题需要解释,因为这两个 regexp 调用非常强大,但每个调用使用的模式看起来真的硬外语。我觉得如果你能解释正在发生的事情,不仅对我加强这个概念有好处,而且对其他人也有好处,这样他们就可以看到正则表达式的强大之处。感谢您的投票:)
    • “包括我!”大声笑你太谦虚了! :)
    • @ViharChervenkov - 完成。看一看。它需要对第二个正则表达式稍作修改。我还添加了一个示例以表明它有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-07
    • 1970-01-01
    • 2011-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-14
    相关资源
    最近更新 更多