Reputation: 2324
In my Groovy program, I have a list of lines and want to select a contiguous block of lines from the list. The first line of the desired block contains a particular string, and the last line (which I can include or not - it doesn't matter) contains a (different) marker string.
Working code is below but surely there is a "groovier" way to do this in a line or two - can anyone suggest how?
(Actually my list of lines is from an HTTP GET, but I just define a URL object and do url.openStream().readLines() to get the lines.)
lines = ["line1", "line2", "line3", "line4", "line5", "line6"]
println extract_block("2", "5", lines)
def extract_block(start, end, lines) {
def block = null
for (line in lines) {
if (null == block && line.contains(start)) { block = [] }
if (null != block && line.contains(end)) { break }
if (null != block) { block << line }
}
return block
}
This prints
["line2", "line3", "line4"]
which includes the first line (containing "2") and skips the final line (containing "5").
Upvotes: 1
Views: 760
Reputation: 2324
A shorter but somewhat less expressive version of Ted's "groovier" answer:
def extract_block(start, end, lines) {
def inBlock = false
return lines.findAll { inBlock = (it.contains(start) || inBlock) && !it.contains(end) }
}
Upvotes: 0
Reputation: 26821
Alternatively, if you don't want to use regular expressions, you can make it a little more groovy using findAll:
lines = ["line1", "line2", "line3", "line4", "line5", "line6"]
def extract_block(start, end, lines) {
def inBlock = false
return lines.findAll { line ->
if (line.contains(start)) inBlock = true
if (line.contains(end)) inBlock = false
return inBlock
}
}
assert ["line2", "line3", "line4"] == extract_block("2", "5", lines)
Upvotes: 0
Reputation: 26821
Regular expressions are designed for this kind of problem. Here's an example that shows it works both where the file contents
(NB: the String.find method is in groovy 1.6.1 and above, prior to that you'd need to modify the syntax slightly)
def BEGIN_MARKER = "2"
def END_MARKER = "5"
def BEGIN_LINE = /.*$BEGIN_MARKER.*\n/
def MIDDLE_LINES = /(.*\n)*?/
def LOOKAHEAD_FOR_END_LINE_OR_EOF = /(?=.*$END_MARKER.*|\Z)/
def FIND_LINES = "(?m)" +
BEGIN_LINE +
MIDDLE_LINES +
LOOKAHEAD_FOR_END_LINE_OR_EOF
def fileContents = """
line1 ipsum
line2 lorem
line3 ipsum
line4 lorem
line5 ipsum
line6 lorem
"""
// prints:
// line2 lorem
// line3 ipsum
// line4 lorem
println fileContents.find(FIND_LINES)
def noEndMarkerFileContents = """
line1 ipsum
line2 lorem
line3 ipsum
line4 lorem
line6 lorem
"""
// prints:
// line2 lorem
// line3 ipsum
// line4 lorem
// line6 lorem
println noEndMarkerFileContents.find(FIND_LINES)
Upvotes: 0