【问题标题】:Matlab: Read in ascii with varying column numbers & different formatsMatlab:以不同列号和不同格式读取 ascii
【发布时间】:2013-05-16 13:04:58
【问题描述】:

我一直在研究一个令人费解的问题,该问题涉及将一个 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 自动找到格式的这种变化) .

你有什么建议吗?

干杯!

【问题讨论】:

  • 似乎每一行都有一种标题,后面有一些数字。假设每个标题字符串的数字数量始终不变是否正确?
  • 不,否则我会知道该怎么做。每行在“标题”之后有 5 或 6 个数字,具体取决于其 E3T 还是 E4Q。在 ND 部分,它始终是“ND # X Y Z”
  • 肮脏的方式:逐行读取并使用regexp解析行...
  • 我也想到了正则表达式,这就是我在这里标记它的原因。但我不能很好地处理正则表达式,并希望有一个更清洁的解决方案;)

标签: regex matlab ascii


【解决方案1】:

我建议你先读取文件中所有带有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)、indicesnodes。请注意,如果您的“索引”多于“节点”或反之亦然,则缺失值将由空矩阵表示。

【讨论】:

  • 您能否解释一下您为什么决定存储 E3T/E4Q 行的前四个数值
  • @anandr 它在问题中这么说:“对于三角形(E3T/E4Q 线)我只对前 4 个数字感兴趣
  • 感谢您提供此解决方案。我明天去看看。到目前为止,anandr 的解决方案对我有用,虽然它有点慢。
  • @Eitan,哦,我错过了,谢谢。我无法猜测哪种方式会更快,但我个人更喜欢您的解决方案,因为更像“MatLab”风格;)+1
  • @Eitan 感谢您的解决方案。不过,我坚持 anandr 的解决方案,因为此时对我来说更容易理解。我真的必须更多地进入正则表达式和字符串解析。谢谢!
【解决方案2】:

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

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);

当然,您必须分别处理以 MESH2DMESHNAMEGM 开头的字符串

【讨论】:

  • 未定义的函数或变量't'。将其更改为 while(feof(fileID)),但仍然没有进入循环。有什么建议吗?
  • 抱歉打错字了,想得比打字快。查看我的更新答案。
  • 对我来说非常好用。非常感谢!不过对于大文件来说有点慢。
猜你喜欢
  • 2013-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-23
  • 2014-05-22
  • 1970-01-01
  • 1970-01-01
  • 2015-04-26
相关资源
最近更新 更多