Groovy从列表中选择行块的方法

Groovy从列表中选择行块的方法,groovy,Groovy,在Groovy程序中,我有一个行列表,希望从列表中选择一个连续的行块。所需块的第一行包含一个特定的字符串,最后一行(我可以包含或不包含,这无关紧要)包含一个(不同的)标记字符串 下面是工作代码,但肯定有一种“更groovier”的方法可以在一两行代码中实现这一点——有人能建议怎么做吗 (实际上,我的行列表来自HTTP GET,但我只是定义了一个URL对象,然后执行URL.openStream().readLines()来获取行。) 其中包括第一行(包含“2”)并跳过最后一行(包含“5”)。正则表

在Groovy程序中,我有一个行列表,希望从列表中选择一个连续的行块。所需块的第一行包含一个特定的字符串,最后一行(我可以包含或不包含,这无关紧要)包含一个(不同的)标记字符串

下面是工作代码,但肯定有一种“更groovier”的方法可以在一两行代码中实现这一点——有人能建议怎么做吗

(实际上,我的行列表来自HTTP GET,但我只是定义了一个URL对象,然后执行URL.openStream().readLines()来获取行。)


其中包括第一行(包含“2”)并跳过最后一行(包含“5”)。

正则表达式是为此类问题设计的。下面的示例显示,它在文件内容

(注意:String.find方法在groovy 1.6.1及更高版本中,在此之前,您需要稍微修改语法)


或者,如果不想使用正则表达式,可以使用findAll使其更具groovy性:

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)

Ted“groovier”答案的一个简短但表达力稍差的版本:


谢谢你,特德。我在下面把它缩短了一点,但这或多或少是我想要的。如果有人能让它更简洁的话,我会很受欢迎的。我试图远离正则表达式,因为它们很难阅读(无论如何对我来说)。有些评论可能会让正则表达式变得有意义,但我宁愿使用一些非常简短且易于理解的语句。
["line2", "line3", "line4"]
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)
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)
def extract_block(start, end, lines) {
    def inBlock = false
    return lines.findAll { inBlock = (it.contains(start) || inBlock) && !it.contains(end) } 
}