@@ -125,6 +125,7 @@ def __init__(self, text):
125125 self .filename , self .revision = self ._parse_draftname ()
126126
127127 self ._authors = None
128+ self ._abstract = None
128129 self ._pagecount = None
129130 self ._status = None
130131 self ._creation_date = None
@@ -274,6 +275,77 @@ def get_creation_date(self):
274275 return self ._creation_date
275276
276277
278+ # ------------------------------------------------------------------
279+ def get_abstract (self ):
280+ """Extract abstract from draft text.
281+ based on: http://wiki.tools.ietf.org/tools/ietfdb/browser/branch/legacy/idst/validate.cgi
282+ """
283+ if self ._abstract :
284+ return self ._abstract
285+ draft_text = "\n " .join (self .lines [:len (self .lines )/ 2 ])
286+
287+ abstract_patterns = [
288+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Status of this Memo\s{0,2}\n)' ,
289+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Editorial Note\s{0,2}\n)' ,
290+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Sub-IP ID Summary\s{0,2}\n)' ,
291+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Table of Contents?\s{0,2}\n)' ,
292+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Conventions used in this document\s{0,2}\n)' ,
293+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Introduction\s{0,2}\n)' ,
294+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Terminology\s{0,2}\n)' ,
295+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Definitions\s\s{0,2}\n)' ,
296+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Background( and Intended Usage)?\s{0,2}\n)' ,
297+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Conventions\s{0,2}\n)' ,
298+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*Requirements\s{0,2}\n)' ,
299+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*motivation\s{0,2}\n)' ,
300+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\s*translation\s{0,2}\n)' ,
301+ r'((Abstract|Summary):?\n+)([\s|\S]+?)(\n\s*Contents?)' ,
302+ r'((Abstract|Summary):?\n+)([\s|\S]+?)(\n\s*0. meta information on this)' ,
303+ r'((Abstract|Summary):?\n+)([\s|\S]+?)(\n\s*0. introduction)' ,
304+ r'((Abstract|Summary):?\s*\n+)(( {3,}.+\n+)+)' ,
305+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+?)((\d\.?)?\n{4,})' ,
306+ r'((Abstract|Summary):?\s*\n+)([\s|\S]+)((\d\.?)[^\n]{10,50}\n{0,2})' ,
307+ ]
308+
309+ abstract = None
310+ for ap in abstract_patterns :
311+ match = re .search (ap , draft_text , re .IGNORECASE )
312+ if match :
313+ abstract = match .group (3 )
314+ break
315+
316+ # Remove possible missed sections
317+ match = re .search (r'([\s|\S]+?)(\n+\s{0,10}(\d\.?)\s{0,10}[^\n]{10,50}\s{0,2}\n)' , abstract or '' )
318+ if match :
319+ abstract = match .group (1 )
320+
321+ if abstract :
322+ cleanup_patterns = [
323+ (r"\n{3,}" , "\n \n " ), (r"\f[\n ]*[^\n]*\n" , "" ),
324+ (r"(?s)(\d{1,3}\.\s*)?(Conventions used in this document|Requirements language).*" , "" ),
325+ (r"(?sm)[\n ]*The key words [\'\"]MUST[\'\"], [\'\"]MUST NOT[\'\"],\n.*$" , "" ),
326+ (r"(?s)\nStatus of [tT]his Memo\n\s{1,2}\n.*$" , "" ),
327+ (r"(?s)(\d{1,3}\.?\s*)?Table of Contents\s{0,2}.*$" , "" ),
328+ (r"(?s)(\d{1,3}\.?\s*)?Status of this memo\s{1,2}\n.*$" , "" ),
329+ (r"(?s)(\d{1,3}\.?\s*)?Editorial note.\n*$" , "" ),
330+ (r"(?s)(\d{1,3}\.?\s*)?Terminology\s{1,2}\n.*$" , "" ),
331+ (r"(?s)(\d{1,3}\.?\s*)?Specification of Requirements\s{1,2}\n.*$" , "" ),
332+ (r"(?s)\s*\d\.?(Abstract|Introduction)?\.{15,}" , "" ),
333+ (r"\n\s*\d\.?\s*[\s|\S]+?\n.*" , "" ),
334+ (r"(?sm)(\(|\[)?to be (deleted|removed) (by|when).*" , "" ),
335+ (r"(?s)\n.$" , "" ), (r"(?m)^[^\n]+\.{10,}\d{1,3}" , "" )
336+ ]
337+ for cp , sub in cleanup_patterns :
338+ e = re .compile (cp , re .IGNORECASE )
339+ abstract = e .sub (sub , abstract )
340+
341+ # wrap long lines without messing up formatting
342+ while re .match ("([^\n ]{72,}?) +" , abstract ):
343+ abstract = re .sub ("([^\n ]{72,}?) +([^\n ]*)(\n |$)" , "\\ 1\n \\ 2 " , abstract )
344+
345+ return abstract .strip ()
346+ return None
347+
348+
277349 # ------------------------------------------------------------------
278350 def get_authors (self ):
279351 """Extract author information from draft text.
@@ -581,6 +653,9 @@ def _printmeta(timestamp, fn):
581653 deststatus = draft .get_status ()
582654 if deststatus :
583655 fields ["docdeststatus" ] = deststatus
656+ abstract = draft .get_abstract ()
657+ if abstract :
658+ fields ["docabstract" ] = abstract
584659
585660 _output (fields )
586661
0 commit comments