Regex Matlab:以ascii格式读取不同的列号&;不同格式

Regex Matlab:以ascii格式读取不同的列号&;不同格式,regex,matlab,ascii,Regex,Matlab,Ascii,我一直在研究一个令人费解的问题,涉及将ascii文件读入matlab,该文件包含两部分不同的格式,第一部分还包括不同的列号 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.

我一直在研究一个令人费解的问题,涉及将ascii文件读入matlab,该文件包含两部分不同的格式,第一部分还包括不同的列号

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);
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);
因此,读入标题以跳转到数据,然后读取第一个字符串和后面的4个数字,然后跳转到行尾并重新启动。但这是行不通的。我只得到一行数据,而不是文件的其余部分。另外,我不知道如何处理文件的第二部分,它从任意数量的数字开始(我当然可以手动查找并输入matlab,但希望matlab自动查找格式的更改)

你有什么建议吗


干杯

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

fileID = fopen(test);
t1 = textscan(fileID, '%s',3);
t2 = textscan(fileID, '%s %d %d %d*[^\n]');
fclose(fileID);
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开头的字符串

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

fileID = fopen(test);
t1 = textscan(fileID, '%s',3);
t2 = textscan(fileID, '%s %d %d %d*[^\n]');
fclose(fileID);
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开头的字符串

我建议您首先使用
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值命名为“索引”,将ND值命名为“节点”。生成的数组
S
包含结构,每个结构都有三个字段:
tag
(E3T或E4Q)、
索引
节点
。请注意,如果您的“索引”多于“节点”,或者反之亦然,则缺少的值将由空矩阵表示。

我建议您首先以字符串形式读取文件的所有行,然后过滤掉您需要的任何内容:

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值命名为“索引”,将ND值命名为“节点”。生成的数组
S
包含结构,每个结构都有三个字段:
tag
(E3T或E4Q)、
索引
节点
。请注意,如果“索引”多于“节点”,或者反之亦然,则缺少的值由空矩阵表示。

似乎每行后面都有一种标题和一些数字。假设每个头字符串的数字量总是恒定的是正确的吗?不,否则我会知道怎么做。根据其E3T或E4Q,每行在“标题”后面有5或6个数字。在ND部分,它总是以“ND#X Y Z”的肮脏方式:逐行读取并使用
regexp
解析行……我也想到了regex,这就是为什么我在这里标记它。但我不能很好地处理regex,希望有一个更干净的解决方案;)似乎每行都有一种标题,后面有一些数字。假设每个头字符串的数字量总是恒定的是正确的吗?不,否则我会知道怎么做。根据其E3T或E4Q,每行在“标题”后面有5或6个数字。在ND部分,它总是以“ND#X Y Z”的肮脏方式:逐行读取并使用
regexp
解析行……我也想到了regex,这就是为什么我在这里标记它。但我不能很好地处理regex,希望有一个更干净的解决方案;)未定义的函数或变量“t”。将其更改为while(feof(fileID)),但仍然没有进入循环。有什么建议吗?对不起,我打字打错了,我想得比打字快。这是我最新的答案。对我来说非常好。谢谢!但是对于大文件来说有点慢。未定义的函数或变量“t”。将其更改为while(feof(fileID)),但仍然没有进入循环。有什么建议吗?对不起,我打字打错了,我想得比打字快。这是我最新的答案。对我来说非常好。谢谢!不过对于大文件来说速度有点慢。你能解释一下为什么你决定存储E3T/E4Q行的前四个数值吗?@anandr在问题中这样说:“对于三角形(E3T/E4Q行),我只对前四个数字感兴趣。”谢谢你的解决方案。我明天去看看。到目前为止,阿南德的解决方案对我很有效,尽管有点慢。@Eitan,哦,我错过了,谢谢。我猜不出哪种方法更快,但我个人更喜欢您的解决方案,因为它更像“MatLab”风格;)+1@Eitan谢谢你的解决方案。不过我还是坚持阿南德的解决方案,因为在这一点上我更容易理解。我真的需要更多地学习正则表达式和字符串解析。非常感谢。你能解释一下为什么你决定存储E3T/E4Q线的前四个数值吗?@anandr在问题中这样说:“对于三角形(E3T/E4Q线),我只对前四个数字感兴趣。”谢谢你的解决方案。我明天去看看。到目前为止,阿南德的解决方案对我很有效,尽管有点慢。@Eitan,哦,我错过了,谢谢。我猜不出哪种方法更快,但我个人更喜欢您的解决方案,因为它更像“MatLab”风格;)+1@Eitan谢谢你的解决方案。不过我还是坚持阿南德的解决方案,因为在这一点上我更容易理解。我真的需要更多地学习正则表达式和字符串解析。非常感谢。