Самый простой способ разобрать файл в MATLAB

Я пытаюсь извлечь контурные точки из текстового файла с помощью MATLAB. Пример линии, содержащей эти точки контура:

Cnt-0-Pt        0/0/146/171/5/146.912065/171.618881/5.500000/0

Обратите внимание, что не каждая строка начинается со строки Cnt-0-Pt (поскольку в этих файлах помимо точек контура есть и другие поля), но каждая строка точки контура всегда имеет 0 в своей строке поля, т. е. нет опции что линия точки контура будет начинаться, например, с Cnt-1-Pt. После этой строки есть пробел и две табуляции. Я хочу извлечь три целых числа после второго / разделителя. В этом примере это будут 146, 171 и 5. Как это сделать проще всего?

Вот пример того, как выглядит текстовый файл

#
# Direction U 
#
U-Number        92
U-Scale         1.470000
#
# Direction V 
#
V-Number        204
V-Scale         1.470000
#
# Direction W 
#
W-Number        16
W-Scale         1.470000
s-base-plane        0
#
#  Video/Recorder Parameters
#
play-mode        toggle
rotate-mode         ObjAxis
d-xrotate       0.000
d-yrotate       0.000
d-zrotate       0.000
#
#  Cut-Oblique Parameters
#
Plane-size      1.470
Plane-2D        off
Plane-3D        off
#
#  ValidVol Parameters
#
validity-field      ignored
#
#  Histogram Parameters
#
histo-scale         1.000000
#
#  VOI Parameters
#
Margin-Mode         2
#
#  VOI Segmentations
#
Slice-Dist-U        0.562500
Slice-Dist-V        0.562500
Slice-Dist-W        3.000000
MVol_Volume         0
#Contour 0 Parameter 
Contour-Start    0
Cnt-0-Contour-name      Prostate
Cnt-0-Contour-color-list        16711680
Cnt-0-Contour-color         16711680
Cnt-0-Contour-Type      0
Cnt-0-Contour-Class         0
Cnt-0-Contour-Mandatory         1
Cnt-0-Contour-num       19
Cnt-0-Inter-Contour-color       12517376
Cnt-0-Segmentation_U        No
Cnt-0-Segmentation_V        No
Cnt-0-Segmentation_W        Yes
Cnt-0-Cnt       919.658969/118.184765/919.658969/118.184765/5
Cnt-0-Pt        0/0/146/171/5/146.912065/171.618881/5.500000/0
Cnt-0-Pt        0/0/148/154/5/148.514670/154.791536/5.500000/0
Cnt-0-Pt        0/0/153/146/5/153.055382/146.511414/5.500000/0
Cnt-0-Pt        0/0/165/139/5/165.876216/139.299695/5.500000/0
Cnt-0-Pt        0/0/178/140/5/178.429949/140.635199/5.500000/0
Cnt-0-Pt        0/0/188/143/5/188.045574/143.306206/5.500000/0
Cnt-0-Pt        0/0/195/152/5/195.524394/152.921831/5.500000/0
Cnt-0-Pt        0/0/203/164/5/203.804516/164.140061/5.500000/0
Cnt-0-Pt        0/0/206/178/5/206.475523/178.563499/5.500000/0
Cnt-0-Pt        0/0/206/191/5/206.475523/191.384333/5.500000/0
Cnt-0-Pt        0/0/204/201/5/204.338717/201.267059/5.500000/0
Cnt-0-Pt        0/0/199/208/5/199.530904/208.745879/5.500000/0
Cnt-0-Pt        0/0/193/213/5/193.387588/213.553691/5.500000/0
Cnt-0-Pt        0/0/186/213/5/186.175869/213.820792/5.500000/0
Cnt-0-Pt        0/0/180/206/5/180.833855/206.876174/5.500000/0
Cnt-0-Pt        0/0/176/198/5/176.026042/198.061851/5.500000/0
Cnt-0-Pt        0/0/169/189/5/169.348525/189.514628/5.500000/0
Cnt-0-Pt        0/0/162/182/5/162.671007/182.570010/5.500000/0
Cnt-0-Pt        0/0/152/177/5/152.254080/177.495096/5.500000/0
Cnt-0-Cnt       1210.414404/141.990846/1210.414404/141.990846/6
Cnt-0-Pt        0/0/173/139/6/173.622136/139.833897/6.500000/0
Cnt-0-Pt        0/0/181/131/6/181.368056/131.286674/6.500000/0
Cnt-0-Pt        0/0/197/129/6/197.126998/129.951171/6.500000/0
Cnt-0-Pt        0/0/207/142/6/207.009724/142.772005/6.500000/0
Cnt-0-Pt        0/0/214/153/6/214.221443/153.990234/6.500000/0

person Filipe    schedule 19.08.2015    source источник
comment
Пожалуйста, опубликуйте минимальный, но полный пример того, как может выглядеть этот файл. что такое строка поля?   -  person m.s.    schedule 19.08.2015
comment
не каждую строчку вижу только одну строчку.   -  person CroCo    schedule 19.08.2015
comment
Извините, я должен был привести полный пример. Это там сейчас   -  person Filipe    schedule 19.08.2015
comment
Часть над первым 'Cnt-0-Pt' всегда имеет одинаковое количество строк или оно различается?   -  person horchler    schedule 19.08.2015
comment
Это переменная. И количество строк «Cnt-0-Pt» также варьируется   -  person Filipe    schedule 19.08.2015
comment
Всегда ли есть одна строка 'Cnt-0-Cnt' прямо перед началом строк 'Cnt-0-Pt'?   -  person horchler    schedule 19.08.2015
comment
Да, есть. И таких строк «Cnt-0-Cnt» больше одной. Я снова обновил пример, чтобы проиллюстрировать   -  person Filipe    schedule 19.08.2015


Ответы (2)


Проблема в том, что у вас фактически есть нетривиальный, переменный заголовок строки и различные элементы, смешанные с интересующими вас данными. Обычно такой файл нужно анализировать построчно (формат файла, вероятно, должен использовать структуру XML), но можно использовать быстрый textscan.

Первый шаг — найти точку в файле, где начинаются 'Cnt-0-Pt' строки. Приведенный ниже код получает по одной строке, используя fgetl, пока не найдет 'Cnt-0-Cnt' строка. Затем textscan используется для чтения остальной части файла и сохранения соответствующих трех столбцов в массиве ячеек.

fid = fopen('test.txt');
while ~strncmp(fgetl(fid),'Cnt-0-Cnt',9)
end
C = textscan(fid,'%*s%*f/%*f/%f/%f/%f/%*s','CommentStyle','Cnt-0-Cnt')
fclose(fid);

Строка формата textscan, '%*s%*f/%*f/%f/%f/%f/%*s' игнорирует первую строку, первые два числа и все, что следует за интересующими вас тремя числами. 'CommentStyle' используется как своего рода уловка для игнорирования любых последующих строк, начинающихся с 'Cnt-0-Cnt'. Более подробные сведения см. в документации textscan. Можно было бы избежать цикла while, добавив все имена полей в массив ячеек 'CommentStyle', например, {'#','U-Number','U-Scale','V-Number',...}.

person horchler    schedule 19.08.2015
comment
Работает отлично. Огромное спасибо за помощь! - person Filipe; 19.08.2015

Менее умная, чуть более явная версия ответа @horchler:

fID = fopen('test.txt', 'r');

ii = 1;
mydata = [];
while ~feof(fID) % Loop until we've reached the end of the file
    tline = fgetl(fID);
    if ~isempty(regexp(tline, 'Cnt-0-Pt', 'Once'))
        % Matched the line we want, parse it
        splitline = regexp(tline, '/', 'split'); % Split along the / delimiter
        tdata = cellfun(@str2double, splitline(3:5), 'UniformOutput', false); % Convert the strings you want to doubles
        mydata(ii,:) = [tdata{:}]; % Pull data out of the cell array
        ii = ii + 1;
    end
end

fclose(fID);

Это проходит через ваш файл строка за строкой, пока не достигнет конца. Если он находит вашу строку Cnt-0-Pt, он анализирует строку для ваших данных, в противном случае строка отбрасывается.

Это может быть очень ресурсоемкий метод для использования, поскольку он не использует ни одну из сильных сторон MATLAB. Поскольку размер и расположение ваших данных являются переменными, вы не можете предварительно выделить или указать MATLAB, где конкретно в файле читать. Хотя в этой ситуации построчный подход может быть единственным хорошим вариантом.

person excaza    schedule 19.08.2015