Regex для поиска пар строк

Я нашел этот отличный скрипт Ганта на http://blog.armbruster-it.de/2010/07/getting-a-list-of-all-i18n-properties-used-in-a-grails.-application/ Спасибо, Стефан!

Описание: создать список всех свойств i18n, используемых в groovy-коде и шаблонах gsp.

def properties = []

new File(".").eachFileRecurse {
    if (it.file) {
        switch (it) {
            case ~/.*\.groovy/:
                def matcher = it.text =~ /code:\s*["'](.*?)["']/
                matcher.each { properties << it[1] }
                break
            case ~/.*\.gsp/:
                def matcher = it.text =~ /code=["'](.*?)["']/
                matcher.each { properties << it[1] }
                break
        }
    }
}
println properties.sort().unique().join("\n")

Я попытался расширить его следующим образом. Допустим, у нас есть свойства сообщения soem, такие как:

message(code: 'product.label', default: 'Product')

Что мы хотим получить на выходе скрипта примерно так:

product.label=Product

Я попытался добавить некоторое условие в регулярное выражение:

def matcher = it.text =~ /code=["'](.*?)["'] | default=\s*["'](.*?)["']/

и заполнить его свойствами. Но поскольку регулярное выражение не находит пары частей «код и по умолчанию», это не сработает.

Любая идея, как изменить регулярное выражение или весь скрипт, чтобы сделать это?


person skurt    schedule 19.04.2011    source источник


Ответы (4)


Ваше регулярное выражение неверно. Для следующего вызова метода сообщения:

message(code: 'product.label', default: 'Product')

Это должно выглядеть так:

def properties = [:]
def txt = "message(code: 'product.label', default: 'Product')"
def matcher = txt =~ /code:\s*["'](.*?)["'].*default:\s*["'](.*?)["']/
matcher.each{ properties[it[1]] = it[2] }
assert properties == ['product.label':'Product']
person Kai Sternad    schedule 19.04.2011
comment
упс, я прочитал ваше решение после того, как опубликую свое. почти то же самое и работает, спасибо! - person skurt; 20.04.2011
comment
когда я работал с этим кодом, я столкнулся с некоторой слабостью: он находит только одно совпадение на строку кода. Чтобы исправить это, мы должны изменить matcher. - person skurt; 26.04.2011
comment
Насколько я понимаю, он даже не смотрит на строки, а на весь текст и на самом деле находит для меня несколько совпадений. Проблема в том, что он (а) находит только соответствия, которые имеют значения по умолчанию, и игнорирует те, у которых их нет, и (б) игнорирует тот факт, что иногда вам придется использовать ${g.message(…)} в файлах .gsp. . - person fluxon; 11.03.2013


лучшее регулярное выражение для его решения:

/code=["'](.*?)["'].*default=\s*["'](.*?)["']/

формат вывода может быть

properties << it[1]+"="+it[2]

полученные результаты

product.label=Product
person skurt    schedule 20.04.2011

Я немного поработал с этим скриптом и нашел некоторые детали, требующие внимания. Я хочу найти сообщения с определенными значениями по умолчанию и без них, а также найти версию без тега (например, ${g.message(code:"the.code", default:"the.default"}).

Кажется хорошим не просматривать содержимое файла, а анализировать его построчно. Это потому, что если в строке есть код, я (на втором этапе) посмотрю, есть ли у него значение по умолчанию. Однако не нужно дважды анализировать весь файл.

def properties = [:]

new File(".").eachFileRecurse { file ->
    if (file.file) {
        switch (file) {
            case ~/.*\.groovy/:
                file.eachLine {line ->
                    // check if there is a message in the current line
                    def matcherNoDefault = line =~ /code:\s*["'](.*?)["']/
                    // if there is one, check if it has a default
                    if (matcherNoDefault.getCount() > 0) {
                        def matcher = line =~ /code:\s*["'](.*?)["'].*default:\s*["'](.*?)["']/
                        if (matcher.getCount() > 0) {
                            matcher.each{ properties[it[1]] = it[2] }
                        } else {
                            matcherNoDefault.each{ properties[it[1]] = "NO_DEFAULT" }
                        }
                    }
                }
                break
            case ~/.*\.gsp/:
                file.eachLine {line ->
                    // check if there is a message in the current line (as a g.message(...) function)
                    def matcherNoDefault = line =~ /code:\s*["'](.*?)["']/
                    // if there is one, check if it has a default
                    if (matcherNoDefault.getCount() > 0) {
                        def matcher = line =~ /code:\s*["'](.*?)["'].*default:\s*["'](.*?)["']/
                        if (matcher.getCount() > 0) {
                            matcher.each{ properties[it[1]] = it[2] }
                        } else {
                            matcherNoDefault.each{ properties[it[1]] = "NO_DEFAULT" }
                        }
                    }

                    // check if there is a message in the current line (in tag form)
                    matcherNoDefault = line =~ /code=["'](.*?)["']/
                    // if there is one, check if it has a default
                    if (matcherNoDefault.getCount() > 0) {
                        def matcher = line =~ /code=["'](.*?)["'].*default=["'](.*?)["']/
                        if (matcher.getCount() > 0) {
                            matcher.each{ properties[it[1]] = it[2] }
                        } else {
                            matcherNoDefault.each{ properties[it[1]] = "NO_DEFAULT" }
                        }
                    }
                }
        }
    }
}
println properties.each {k, v ->
    println("${k}=${v}")
}

Таким образом, я не могу смешивать сообщения со значением по умолчанию и без него в одной строке. Я могу жить с этим пока.

Радоваться, веселиться!

person fluxon    schedule 11.03.2013