Regex Multiple lines

I try to write regex for multiple lines parsing. Here, this is powerfull example…

Idea

I want classify a set of regex into various category. Regex can be single line or mutiple line.

<regex>
  <line>file not found</line>
</regex>
<regex>
  <select>
    <start>There was 1 failure:</start>
    <end>FAILURES!!!</end>
  </select>
</regex>

For each expression, I can associate a type, title, message. And, the final configuration is :

<xml>
  <check>
    <title>IT error</title>
    <type>it</type>
    <message>File not found</message>
    <regex>
	<line>file not found</line>
    </regex>
   </check>
</xml>

I thinks this example is clear enough to understand the functionnaly if you take a couple of second to look at the example.

Sources

Input

def source = """\
[java] Libary io_gppr_cmos32lp_t18_mv11_mv18_tl25_rvt_dr -- library Spice file spice/io_gppr_cmos32lp_t18_mv11_mv18_tl25_rvt_dr_ctypical_25c_5U1x_2T8x_LB.spice: retained.
[java] Library io_gppr_cmos32lp_t18_mv11_mv18_tl25_rvt_dr -- library Spice file spice/io_gppr_cmos32lp_t18_mv11_mv18_tl25_rvt_dr_cworst_125c_5U1x_2T8x_LB.spice: retained.
[java] Library io_gppr_cmos32lp_t18_mv11_mv18_tl25_rvt_dr -- library Spice file spice/io_gppr_cmos32lp_t18_mv11_mv18_tl25_rvt_dr_cbest_25c_5U1x_2T8x_LB.spice: retained.
[java] Library io_gppr_cmos32lp_t18_mv11_mv18_tl25_rvt_dr -- Siliconsmart IBIS merge char point ibis-characterizer/normal/.ibis_merge: skipped.
[java] Library io_gppr_cmos32lp_t18_mv11_mv18_tl25_rvt_dr -- SiliconSmart configure.tcl file ibis-characterizer/normal/merge/config/configure.tcl: skipped.
[java] Library io_gppr_cmos32lp_t18_mv11_mv18_tl25_rvt_dr -- Merged 3 PVT IBIS file ibis/io_gppr_cmos32lp_t18_mv11_mv18_tl25_rvt_dr.ibs: skipped.
[java]
[java] Checking library...
[java] Program done.
[java] file not found  
[java] Test Finished: testIOIBISOnly3PvtMerge, Time: 2010/03/10 04:53:30.257000000
[java] Java Vendor: Sun Microsystems Inc.
[java] Java Version: 1.6.0_11
[java] Operating System: Linux
[java] Total Run Time: 10354.774 Seconds
[java] F
[java] Time: 10,355.323
[java] There was 1 failure:
[java] 1) testIOIBISOnly3PvtMerge(com.arm.cellbuilder.iotest.TestIOCellBuilder)junit.framework.AssertionFailedError: Logs from gold/test doesn't match
[java]     at com.arm.cellbuilder.iotest.TestIOCellBuilder.checkLogs(TestIOCellBuilder.java:1416)
[java]     at com.arm.cellbuilder.iotest.TestIOCellBuilder.testIOIBISOnly3PvtMerge(TestIOCellBuilder.java:1147)
[java]     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
[java]     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
[java]     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[java]     at com.arm.cellbuilder.iotest.TestIOCellBuilder.main(TestIOCellBuilder.java:75)
[java]
[java] FAILURES!!!
[java] Tests run: 1,  Failures: 1,  Errors: 0
[java]

 BUILD SUCCESSFUL
 Total time: 172 minutes 40 seconds
 ERROR"""

Configuration

def config = """\
                <xml>
                        <check>
                                <title>IT error</title>
                                <type>it</type>
                                <message>File not found</message>
                                <regex>
                                        <line>file not found</line>
                                </regex>
                        </check>
                        <check>
                                <title>JUnit stacktrace</title>
                                <type>developer</type>
                                <message>JUnit</message>
                                <regex>
                                        <select>
                                                <start>There was 1 failure:</start>
                                                <end>FAILURES!!!</end>
                                        </select>
                                </regex>
                        </check>
                </xml>
                """

Groovy

def checker = { input,  configuration ->
        // TODO: Apply selector one by one
        def conf = new XmlParser().parseText(configuration)
 
        def stats = []  //TODO: Check if title unique
 
        def modeMultiline = false
 
        // Read file line by line
        input.eachLine{ line ->
                def title = ""
                def message = ""
                conf.check.each{
 
                        title = it.title.text()
                        message = it.message.text()
 
                        assert title
 
                        // Single line error detection
                        if(!modeMultiline){
                                it.regex.line.each{
                                        if(line ==~ /^.*${it.text()}.*$/){
                                                stats << title
                                                println message
                                        }
                                }
                        }
 
                        // Select interesting part of the report
                        it.regex.select.each{
                                if(!modeMultiline){
                                      if(line ==~ /^.*${it.start.text()}.*$/){
                                              modeMultiline = true
                                              println "${message}       >>>>>>"
                                      }
                                    }else{
                                       if(line ==~ /^.*${it.end.text()}.*$/){
                                               modeMultiline = false
                                               stats << title
                                               println "<<<<<<<<"
                                        }else{
                                                if(line ==~ /^.*[java].*/  && line.size() > 8)
                                                        println line.substring(9)
                                        }
                                    }
                        }
                }
        }
 
        return stats
}
 
def stats = checker(source, config)
 
assert stats.size() == 2
 
// Associate title -> type
def map = [:]
stats.each{ title ->
        new XmlParser().parseText(config).check.each{
                if(it.title.text() == title){
                        if(map[it.title.text()] == null){
                                map[it.type.text()] = 1
                        }else{
                                map[it.type.text()]++
                        }
                }
        }
}
// Display result
map.each{ key, value ->
        println "${key}:${value}"
}

Conclusion

It works perfectly and more over the execution time is really efficient…