3
$\begingroup$

I have a plain text file with some data. I need two things:

  1. Be able to extract certain values for the various field, e.g. to extract the 'Mean Dose [%]', that is to extract number 103.3, and
  2. Get a list of lists with the numbers after the line containing 'Relative Dose [%]', e.g. {0.5, 22.5, 0}, ... }.

Note: The data files are generated from another program, so their format is always the same. No need to take measures to be robust while parsing to cover edge cases.

Normally:

  1. I would write an ad-hoc program in C to get the data I'm interested in. How do you approach such parsing problems with Mathematica?

For example is there a command that searches in a list of tuples for a string as the 1st element returning the 2nd element ? Like (pseudocode):

dat = Import["~/myfile"];
dat[["Mean Dose [%]"]]
(* returns 103.3 *) 
  1. I would probably edit the files manually removing all text including the Relative Dose [%]' and then import the rest similar to CSV files or so.

Here follows a part of the data file:

Patient Name         : XXXXX, XXXXX (XXXX/XX), ()
Patient ID           : XXXX/XX
Comment              : DVHs for one plan
Date                 : 19.09.2014  13:53:00
Type                 : Differential Dose Volume Histogram
Description          : The differential DVH displays the share of the total
                       volume in structures receiving a given dose as
                       a function of equivalent dose intervals. In the data,
                       below, dose values correspond to the center of the
                       dose interval.

Plan: 3FIF ST
Prescribed dose [cGy]: 4500.0
% for dose (%): 100.0

Structure: PTV
Approval Status: Approved
Plan: 3FIF ST
Course: C1
Volume [cm³]: 370.8
Dose Cover.[%]: 100.0
Sampling Cover.[%]: 100.0
Min Dose [%]: 89.7
Max Dose [%]: 108.3
Mean Dose [%]: 103.3
Modal Dose [%]: 107.2
Median Dose [%]: 103.6
STD [%]: 2.9
Equiv. Sphere Diam. [cm]: N/A
Conformity Index: N/A
Gradient Measure [cm]: N/A

Relative dose [%]          Dose [cGy] dVolume / dDose [cm³ / %]
              0.5                22.5                         0
              1.5                67.5                         0
              2.5               112.5                         0
              3.5               157.5                         0
              4.5               202.5                         0
              5.5               247.5                         0
              6.5               292.5                         0
              7.5               337.5                         0
              8.5               382.5                         0
              9.5               427.5                         0
             10.5               472.5                         0
             11.5               517.5                         0
             12.5               562.5                         0
$\endgroup$
6
$\begingroup$

For the first case, one way will be to read the entire file as a String and manipulate it e.g:

txt = ReadList["dose.txt", String];

Then do something like:

Flatten @ StringCases[txt, "Mean Dose [%]: " ~~ (x : NumberString) -> ToExpression @ x]

{103.3}

I guess you can turn it into a function:

sValues[s_String] := Flatten @ StringCases[txt, s ~~ (x : NumberString) :> ToExpression @ x]

Then:

sValues["Mean Dose [%]: "]

{103.3}

sValues["Max Dose [%]: "]

{108.3}

And so on...

For the second case, if you know the number of lines you want to skip until you get to the data then the following should work fine:

readFile[file_String?FileExistsQ, n_Integer] := Module[{str = OpenRead[file], data},
  Skip[str, String, n];
  data = ReadList[str, Table[Number, {3}]];
  Close[str];
  data
 ]

Use:

readFile["dose.txt", 30]
{{0.5, 22.5, 0}, {1.5, 67.5, 0}, {2.5, 112.5, 0}, {3.5, 157.5, 0}, 
 {4.5, 202.5, 0}, {5.5, 247.5, 0}, {6.5, 292.5, 0}, {7.5, 337.5, 0}, 
 {8.5, 382.5, 0}, {9.5, 427.5, 0}, {10.5, 472.5, 0}, {11.5, 517.5, 0}, {12.5, 562.5, 0}} 

Another possibility for the second case:

StringSplit[Flatten @ StringCases[txt, Repeated[Whitespace ~~ NumberString, {3}]],
            Whitespace] // ToExpression
{{0.5, 22.5, 0}, {1.5, 67.5, 0}, {2.5, 112.5, 0}, {3.5, 157.5, 0}, 
 {4.5, 202.5, 0}, {5.5, 247.5, 0}, {6.5, 292.5, 0}, {7.5, 337.5, 0},  
 {8.5, 382.5, 0}, {9.5, 427.5, 0}, {10.5, 472.5, 0}, {11.5, 517.5, 0}, {12.5, 562.5, 0}}
$\endgroup$
  • $\begingroup$ Thanks @RunnyKine! I suppose I can extract the values I'm interested in and then chop all first N lines to parse the columns. $\endgroup$ – stathisk Sep 19 '14 at 15:07
  • $\begingroup$ @Zet, yes you can. But I may add something to my answer for the second part soon. $\endgroup$ – RunnyKine Sep 19 '14 at 15:08
  • $\begingroup$ @Zet. Thanks for the accept, see my update. $\endgroup$ – RunnyKine Sep 19 '14 at 15:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.