2015-06-01 95 views
1

我想從文本文件中提取數字。 首先,我讀文件和進口是爲形式的單元陣列:MATLAB - 從字符串數組中提取數字

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 

代替,但我得到NaN的所有值M.

回答

3

這是使用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返回匹配發生位置的索引

第一個regexp調用查找在字符串的開頭處出現的一系列數字。 \d+意味着查找一個或多個數字,並且^意味着在字符串的開頭查找,因此將這兩者結合起來表示您要在字符串的開頭尋找一串數字。我假設字符串的開頭是一個整數,所以我們可以逃避這一點。將返回的是單元格數組,其中每個條目是另一個單元格的匹配數組。如果這樣做,我們應該得到一個單元陣列,每個單元都有一個1 x 1的單元格,每個單元格都是開頭的數字。

第二regexp呼叫查找數的序列,使得有任選一串數字(\d*),隨後是可選的小數點(\.?),隨後至少1號(\d+),然後任選我們尋找一個e字符,-字符和另一串數字在此之後(\d+)。請注意,這些都是通過(e-\d+)?分組在一起的,這意味着這個指數的東西是可選的。此外,整個模式全部出現在字符串的末尾,因此括號將所有這些令牌分組在一起並以$結束,這意味着查看字符串的末尾*字符表示查找零次或多次出現,而?字符表示查找零次或一次出現。爲了保持一致,+字符表示尋找一個或多個事件。

請注意,正則表達式中的.字符表示通配符或任何字符。如果您明確想要與小數點匹配,則需要在.字符前添加\。因此,正則表達式是在字符串的末尾找到模式,我們可以在可選小數點之前選擇一組數字,然後至少有一個數字跟隨這兩個可選項。這將與第一個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 
+1

我不會將這些信息添加到所有我的答案中:D Well解釋! +1 –

+1

@rayryeng一如既往的輝煌!謝謝! – Trenera

+1

@SanthanSalai - 謝謝:)正則表達式我覺得他們**總是**需要很多解釋。這是一種黑人藝術,很多人都不太明白(包括我),所以使用它們的問題需要解釋,因爲這兩個'regexp'調用非常強大,但每次調用的模式看起來都像一個真正的硬的外語。我覺得,如果你能解釋發生了什麼事情,那麼不僅對增強概念有利,而且對其他人也有利,這樣他們就能看到正則表達式的強大程度。感謝您的投票:) – rayryeng