Matlab:使用不同的列数读入ascii&不同的格式

时间:2013-05-16 13:04:58

标签: regex matlab ascii

我一直在研究一个令人费解的问题,即将ascii文件读入matlab,其中包含2个不同格式的部分,第一部分还包括不同的列号。

MESH2D
MESHNAME "XXX"
E3T 1 1 29 30 1
E4Q 2 2 31 29 1 1
E4Q 3 31 2 3 32 1
...
...
...
ND 120450 5.28760039e+004 7.49260000e+004 8.05500000e+002
ND 120451 5.30560039e+004 7.49260000e+004 6.84126709e+002
ND 120452 5.32360039e+004 7.49260000e+004 6.97750000e+002
ND 120453 5.34010039e+004 7.49110000e+004 7.67000000e+002
NS  1 2 3 4 5 6 7 8 9 10
NS  11 12 13 14 15 16 17 18 19 20
NS  21 22 23 24 25 26 27 -28
BEGPARAMDEF
GM  "Mesh"

我只对包含三角形的行感兴趣,并以E3T / E4Q开头,并且相应的行包含三角形节点的坐标并以ND开头。对于三角形(E3T / E4Q线),我只关注前4个数字,因此我试图做这样的事情:

fileID = fopen(test);
t1 = textscan(fileID, '%s',3);
t2 = textscan(fileID, '%s %d %d %d*[^\n]');
fclose(fileID);

因此,在标题中读取以跳转到数据,然后读取第一个字符串并跟随4个数字,然后跳转到行尾并重新启动。但这不起作用。我只获得一行数据,而不是文件的其余部分。另外,我不知道如何处理文件的第二部分,它以任意数量的数字开始(我当然可以手动查找并输入matlab,但更喜欢matlab自动找到格式的这种更改)

你有什么建议吗?

干杯!

2 个答案:

答案 0 :(得分:2)

我建议你先用textscan作为字符串读取文件的所有行,然后过滤掉你需要的任何内容:

fid = fopen(filename, 'r');
C = textscan(fid, '%s', 'delimiter', '');
fclose(fid);

然后使用regexp解析E3T / E4Q / ND线:

C = regexp(C, '(\w*)(.*)', 'tokens');
C = cellfun(@(x){x{1}{1}, str2num(x{1}{2})}, C, 'UniformOutput', false);
C = vertcat(C{:});

然后将相应的E3T / E4Q和ND线分组:

idx1 = strcmp(C(:, 1), 'E3T') | strcmp(C(:, 1), 'E4Q');
idx2 = strcmp(C(:, 1), 'ND');
N = max(nnz(idx1), nnz(idx2));
indices = cellfun(@(x)x(1:4), C(idx1, 2), 'UniformOutput', false);
S = struct('tag', [C(idx1, 1); cell(N - nnz(idx1), 1)], ...
    'indices', [indices; cell(N - nnz(idx1), 1)], ...
    'nodes', [C(idx2, 2); cell(N - nnz(idx2), 1)]);

我将E3T / E4Q值命名为“indices”,将ND值命名为“nodes”。生成的数组S包含结构,每个结构包含三个字段:tag(E3T或E4Q),indicesnodes。请注意,如果您有“索引”而不是“节点”,反之亦然,则缺失值由空矩阵表示。

答案 1 :(得分:1)

我知道这并不完美,但如果你的文件不是太大,你可以做这样的事情:

fileID = fopen(test,'r');
while ~feof(fileID)
    FileLine        = fgetl(fileID);
    [LineHead,Rem]  = strtok(FileLine);     % separated string header and numbers
    switch LineHead
        case 'MESH2D'
            % do something here
        case 'MESHNAME'
            % do something here
        case 'E3T'
            % parse integer numbers
            [Num,NumCount]  = sscanf(Rem, '%d');
        case 'E4Q'
            % parse integer numbers
            [Num,NumCount]  = sscanf(Rem, '%d');
        case 'ND'
            % parse integer numbers
            [Num,NumCount]  = sscanf(Rem, '%d');

            % or if you prefer to parse first number separately
            [strFirst,strOthers]    = strtok(Rem);
            FirstInteger            = str2num(strFirst);
            [Floats,FloatsCount]    = sscanf(strOthers, '%g');
        % and so on...
    end
end
fclose(fileID);

当然,您必须单独处理以 MESH2D MESHNAME GM 开头的字符串