Uberto
Uberto

Reputation: 2712

How to parse text in Groovy

I need to parse a text (output from a svn command) in order to retrieve a number (svn revision). This is my code. Note that I need to retrieve all the output stream as a text to do other operations.

def proc = cmdLine.execute()                 // Call *execute* on the strin
proc.waitFor()                               // Wait for the command to finish
def output = proc.in.text

//other stuff happening here

output.eachLine {
    line ->
    def revisionPrefix = "Last Changed Rev: "
    if (line.startsWith(revisionPrefix)) res = new Integer(line.substring(revisionPrefix.length()).trim())
}

This code is working fine, but since I'm still a novice in Groovy, I'm wondering if there were a better idiomatic way to avoid the ugly if...

Example of svn output (but of course the problem is more general)

Path: .
Working Copy Root Path: /svn
URL: svn+ssh://svn.company.com/opt/svnserve/repos/project/trunk
Repository Root: svn+ssh://svn.company.com/opt/svnserve/repos
Repository UUID: 516c549e-805d-4d3d-bafa-98aea39579ae
Revision: 25447
Node Kind: directory
Schedule: normal
Last Changed Author: ubi
Last Changed Rev: 25362
Last Changed Date: 2012-11-22 10:27:00 +0000 (Thu, 22 Nov 2012)

I've got inspiration from the answer below and I solved using find(). My solution is:

def revisionPrefix = "Last Changed Rev: "
def line = output.readLines().find { line -> line.startsWith(revisionPrefix) }
def res = new Integer(line?.substring(revisionPrefix.length())?.trim()?:"0")

3 lines, no if, very clean

Upvotes: 0

Views: 7349

Answers (1)

tim_yates
tim_yates

Reputation: 171114

One possible alternative is:

def output = cmdLine.execute().text
Integer res = output.readLines().findResult { line ->
  (line =~ /^Last Changed Rev: (\d+)$/).with { m ->
    if( m.matches() ) {
      m[ 0 ][ 1 ] as Integer
    }
  }
}

Not sure it's better or not. I'm sure others will have different alternatives

Edit:

Also, beware of using proc.text. if your proc outputs a lot of stuff, then you could end up blocking when the inputstream gets full...

Here is a heavily commented alternative, using consumeProcessOutput:

// Run the command
String output = cmdLine.execute().with { proc ->

  // Then, with a StringWriter
  new StringWriter().with { sw ->

    // Consume the output of the process
    proc.consumeProcessOutput( sw, System.err )

    // Make sure we worked
    assert proc.waitFor() == 0

    // Return the output (goes into `output` var)
    sw.toString()
  }
}

// Extract the version from by looking through all the lines
Integer version = output.readLines().findResult { line ->

  // Pass the line through a regular expression
  (line =~ /Last Changed Rev: (\d+)/).with { m ->

    // And if it matches
    if( m.matches() ) {

      // Return the \d+ part as an Integer
      m[ 0 ][ 1 ] as Integer
    }
  }
}

Upvotes: 1

Related Questions