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

时间:2009-05-30 13:08:26

标签: groovy

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

工作代码在下面,但肯定有一种“更加通常”的方法可以在一两行中做到这一点 - 任何人都可以提出建议吗?

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

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
}

打印

["line2", "line3", "line4"]

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

3 个答案:

答案 0 :(得分:0)

正则表达式是针对此类问题而设计的。这是一个示例,显示它适用于文件内容

的位置

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

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)

答案 1 :(得分:0)

或者,如果您不想使用正则表达式,可以使用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)

答案 2 :(得分:0)

一个较短但有点不那么富有表现力的特德版“回复”的答案:

def extract_block(start, end, lines) {
    def inBlock = false
    return lines.findAll { inBlock = (it.contains(start) || inBlock) && !it.contains(end) } 
}