]> Creatis software - gdcm.git/blob - Dicts/ParseDict.py
ENH: Adding a python parser for the pdftotext output. Run as: python ParseDict.py...
[gdcm.git] / Dicts / ParseDict.py
1 #! /usr/bin/env python
2 """
3 Let's write our own python parser to clean up the pdf (after 
4 pdftotext of course). 
5 Instructions: run pdftotext like this:
6
7 $ pdftotext -f 9 -l 81 -raw -nopgbrk 04_06PU.PDF 04_06PU-3.txt
8
9 then run the python parser like this:
10
11 $ python ParseDict.py 04_06PU.txt dicomV3.dic
12 """
13 import re,os
14
15 """
16 PdfTextParser takes as input a text file (produced by pdftotext)
17 and create as output a clean file (ready to be processed) by
18 DicomV3Expander
19 Warning: PdfTextParser does not expand:
20 - (xxxx,xxxx to xxxx) xxxxxxxxxxxx
21 or
22 - (12xx, 3456) comment...
23
24 """
25 class PdfTextParser:
26   # Cstor
27   def __init__(self):
28     self._InputFilename = ''
29     self._OutputFilename = ''
30     self._Infile = 0
31     self._OutLines = []
32     self._PreviousBuffers = []
33
34   def SetInputFileName(self,s):
35     self._InputFilename = s
36
37   def SetOutputFileName(self,s):
38     self._OutputFilename = s
39   
40   # Function returning if s is a comment for sure
41   def IsAComment(self,s):
42     #print s,  len(s)
43     if s == "Tag Name VR VM":
44       return True
45     elif s == "PS 3.6-2003":
46       return True
47     elif s == "PS 3.6-2004":
48       return True
49     patt = re.compile('^Page [0-9]+$') 
50     if( patt.match(s) ):
51       return True
52     return False
53
54   def IsAStartingLine(self,s):
55     patt = re.compile('^\\([0-9a-fA-Fx]+,[0-9a-fA-F]+\\) (.*)$') 
56     if( patt.match(s) ):
57       return True
58     return False
59
60   def IsAFullLine(self,s):
61     patt = re.compile('^\\([0-9a-fA-Fx]+,[0-9a-fA-F]+\\) (.*) [A-Z][A-Z] [0-9]$')
62     if( patt.match(s) ):
63       return True
64     return False
65
66   # FIXME this function could we avoided...
67   def IsSuspicious(self,s):
68     l = len(s)
69     if l > 80:
70       return True
71     return False
72
73   def AddOutputLine(self,s):
74     assert not self.IsAComment(s)
75     self._OutLines.append(s + '\n')
76
77   def Open(self):
78     self._Infile = file(self._InputFilename, 'r')
79     for line in self._Infile.readlines():
80       line = line[:-1] # remove '\n'
81       if not self.IsAComment( line ):
82         if self.IsAStartingLine(line):
83           #print "Previous buffer:",self._PreviousBuffers
84           previousbuffer = ' '.join(self._PreviousBuffers)
85           if self.IsAStartingLine(previousbuffer):
86             if not self.IsSuspicious(previousbuffer):
87               self.AddOutputLine(previousbuffer)
88             else:
89               # this case should not happen if I were to rewrite the
90               # thing I should be able to clean that
91               #print "Suspicious:", previousbuffer
92               #print "List is:", self._PreviousBuffers
93               s = self._PreviousBuffers[0]
94               if self.IsAFullLine(s):
95                 # That means we have a weird line that does not start
96                 # as usual (xxxx,xxxx) therefore we tried constructing
97                 # a buffer using a the complete previous line...
98                 #print "Full line:", s
99                 self.AddOutputLine(s)
100                 s2 = ' '.join(self._PreviousBuffers[1:])
101                 #print "Other Full line:", s2
102                 self.AddOutputLine(s2)
103               else:
104                 # we have a suspicioulsy long line, so what that could
105                 # happen, let's check:
106                 if self.IsAFullLine(previousbuffer):
107                   self.AddOutputLine(previousbuffer)
108                 else:
109                   # This is the only case where we do not add
110                   # previousbuffer to the _OutLines
111                   print "Suspicious and Not a full line:", s
112           else:
113             if previousbuffer:
114               print "Not a buffer:", previousbuffer
115           # We can clean buffer, since only the case 'suspicious' +
116           # 'Not a full line' has not added buffer to the list
117           self._PreviousBuffers = []
118           # In all cases save the line for potentially growing this line
119           assert not self.IsAComment(line)
120           self._PreviousBuffers.append(line)
121         else:
122           #print "Not a line",line
123           assert not self.IsAComment(line)
124           self._PreviousBuffers.append(line)
125       else:
126         #print "Comment:",line
127         previousbuffer = ' '.join(self._PreviousBuffers)
128         if previousbuffer and self.IsAStartingLine(previousbuffer):
129           #print "This line is added:", previousbuffer
130           self.AddOutputLine( previousbuffer )
131         else:
132           #print "Line is comment:", line
133           print "Buffer is:", previousbuffer
134         # Ok this is a comment we can safely clean the buffer:
135         self._PreviousBuffers = []
136     self.Write()
137
138   def Write(self):
139     outfile = file(self._OutputFilename, 'w')
140     outfile.writelines( self._OutLines )
141     outfile.close()
142     self._Infile.close()
143     
144   # Main function to call for parsing
145   def Parse(self):
146     self.Open()
147
148 """
149 This class is meant to expand line like:
150 - (xxxx,xxxx to xxxx) xxxxxxxxxxxx
151 or
152 - (12xx, 3456) comment...
153
154 """
155 class DicomV3Expander:
156   def __init__(self):
157     self._InputFilename = ''
158     self._OutputFilename = ''
159     self._OutLines = []
160
161   def SetInputFileName(self,s):
162     self._InputFilename = s
163
164   def SetOutputFileName(self,s):
165     self._OutputFilename = s
166  
167   # Function to turn into lower case a tag:
168   # ex: (ABCD, EF01) -> (abcd, ef01)
169   def LowerCaseTag(self,s):
170     #print "Before:", s[:-1]
171     patt = re.compile('^(\\([0-9a-fA-F]+,[0-9a-fA-F]+\\))(.*)$')
172     m = patt.match(s)
173     if m:
174       s1 = m.group(1)
175       s2 = m.group(2)
176       return s1.lower() + s2
177     else:
178       print "Impossible case:", s
179       os.sys.exit(1)
180
181   def AddOutputLine(self,s):
182     if s.__class__ == list:
183       for i in s:
184         self._OutLines.append(i + '\n')
185     else:
186       self._OutLines.append(s + '\n')
187
188   # Expand the line approriaetkly and also add it to the
189   # _OutLines list
190   def ExpandLine(self, s):
191     assert s[-1] == '\n'
192     s = s[:-1]  # remove \n
193     list = []
194     if self.NeedToExpansion(s, list):
195       self.AddOutputLine(list) # list != []
196     elif self.NeedXXExpansion(s, list):
197       self.AddOutputLine(list) # list != []
198     else:
199       self.AddOutputLine(self.LowerCaseTag(s))
200
201   # If line is like:
202   # (0020,3100 to 31FF) Source Image Ids RET
203   def NeedToExpansion(self,s, list):
204     patt = re.compile('^\\(([0-9a-fA-F]+),([0-9a-fA-F]+) to ([0-9a-fA-F]+)\\)(.*)$')
205     m = patt.match(s)
206     if m:
207       #print m.groups()
208       gr = m.group(1)
209       el_start = '0x'+m.group(2)
210       el_end = '0x'+m.group(3)
211       for i in range(eval(el_start), eval(el_end)):
212         el = hex(i)[2:]
213         l = '('+gr+','+el+')'+m.group(4)
214         list.append(l)
215       return True
216     return False
217
218   # If line is like:
219   # (50xx,1200) Number of Patient Related Studies IS 1
220   def NeedXXExpansion(self,s,list):
221     patt = re.compile('^\\(([0-9a-fA-F]+)xx,([0-9a-fA-F]+)\\)(.*)$')
222     m = patt.match(s)
223     if m:
224       #print m.groups()
225       gr_start = m.group(1)
226       el = m.group(2)
227       #el_start = '0x'+m.group(2)
228       #el_end = '0x'+m.group(3)
229       start = '0x'+gr_start+'00'
230       end   = '0x'+gr_start+'FF'
231       for i in range(eval(start), eval(end)):
232         gr = hex(i)[2:]
233         l = '('+gr+','+el+')'+m.group(3)
234         #print l
235         list.append(l)
236       return True
237     return False
238
239   def Write(self):
240     outfile = file(self._OutputFilename, 'w')
241     outfile.writelines( self._OutLines )
242     outfile.close()
243
244   def Expand(self):
245     infile = file(self._InputFilename,'r')
246     for line in infile.readlines():
247       # ExpandLine also LowerCase the line
248       self.ExpandLine(line) # l is [1,n] lines
249     self.Write()
250     infile.close()
251
252 if __name__ == "__main__":
253   argc = len(os.sys.argv )
254   if ( argc < 3 ):
255     print "Sorry, wrong list of args"
256     os.sys.exit(1) #error
257
258   inputfilename = os.sys.argv[1]
259   outputfilename = os.sys.argv[2]
260   tempfile = "/tmp/mytemp"
261   dp = PdfTextParser()
262   dp.SetInputFileName( inputfilename )
263   #dp.SetOutputFileName( outputfilename )
264   dp.SetOutputFileName( tempfile )
265   dp.Parse()
266
267   exp = DicomV3Expander()
268   exp.SetInputFileName( tempfile )
269   exp.SetOutputFileName( outputfilename )
270   exp.Expand()
271
272
273   #print dp.IsAStartingLine( "(0004,1212) File-set Consistency Flag US 1\n" )