понедельник, 17 января 2011 г.

Groovy - регулярные выражения на уровне синтаксиса языка

По сравнению с Java, в Groovy регекспы поддерживаются на уровне языка. Маленький пример.

def source = 'this is some string just string plain string'

// во-первых, есть спец. форма записи строки, 
//в которой не требуется квотирование
word = /\w+/ 

// оператор ~ позволяет прекомпилировать объект паттерна (так же поддерживает
// подстановку подстрок). wholePattern тут - объект типа java.util.regex.Pattern
wholePattern = ~/($word $word)*/ 

// это проверка (оператором ==~) что вся строка содержит 
// только слова, разделенные пробелами.
assert source ==~ wholePattern 

// А это матчинг, операторв =~ создает объект матчера (java.util.regex.Macher).
// Проверяем, что данному паттерну сооттствует три подстроки
def finder = (source =~ "st..ng*")
assert finder.getCount() == 3

9 комментариев:

  1. Этот комментарий был удален автором.

    ОтветитьУдалить
  2. Предыдущее сообщение сломал парсер :(

    regexp match(str)
    {
    | <#(?< x : int >\d+)#> => WriteLine(x) // x имеет тип int
    | <#(?< x >[a..z]+)#> => WriteLine(x) // x имеет тип string
    | _ => WriteLine("не число и не буквы")
    }

    ОтветитьУдалить
  3. Это наш макрос regexp match :)




    (какой же неудобный этот блогспот, мало того, что умудряется в
    Хроме тормозить, еще и комментировать неудобно)

    ОтветитьУдалить
  4. Хм, странно - у меня в хроме ниче не тормозит.

    А можно немного подробнее для тех кто в танка, как этот макрос примерно работает и что делает? На вид похоже нечто вроде switch-a, где в качестве кейсов - регексы? Или я неправ?

    ОтветитьУдалить
  5. Да, это match в кейсах которого находятся строки - регулярные выражения .NET, при том макрос их разбирает и находит именованые группы (?< >....), для которых создает переменные. При удачном сопоставлении эти переменные получают значение из спосоставляемой строки. В сущности эта штука компилируется в лесенку if-ов.




    А с Хромом разобрался - заблокировал AdBlock-ом фоновое изображение (оно абсолютно спозиционировано и растянуто). Прокрутка блога стала заметно легче.

    ОтветитьУдалить
  6. Ах да, забыл рассказать про <# #>. В Nemerle есть три типа строковых литералов:

    1) "..." обычный литерал, в сишном стиле, для него работают стандартные сишные и юникодные эскейп-последовательности

    2) @"..." вербатим-литерал, как в C#, для него есть только одна эскейп-последовательность - это идущие подряд две двойные кавычки. Сишные и юникодные эскейпы игнорируются. Удобна для записи путей на диске (не нужно экранировать слэши).

    3) <#...#> рекурсивная строка. Может содержать что угодно - даже пары <# #>. Используется для записи литералов, содержащих кавычки и для построения DSL-ей, например LINQ и XML-литералы сделан на этих строках.

    ОтветитьУдалить
  7. Чтож, удобно. В груви есть наверное, 5 типов строковых литералов. Обычный строки, многострочные обычные строки, GStrings (строки в которых резолвятся выражения типа "My name is ${user.name}", многострочные GString, и /.../ строки, внутри которых не надо эскейпить \w, \d, и прочие классы символов - удобно для регулярок.

    ОтветитьУдалить
  8. Да, $-нотация это крутая штука (называются сплайсы), мне их отчаянно нехватает в C# (string.Format сливает) :(
    А Nemerle умеет вот так:

    def name = "Mary";
    def fruits = [ "apple", "orange", "lime" ];
    $<#$name has ..$(fruits; ", ").#>

    На выходе получится строка:

    "Mary has apple, orange, lime."

    Понимает следующие эскейпы: $имя, $(выражение), ..$(коллекция; разделитель).

    ОтветитьУдалить
  9. Ну в груви строго говоря внутри фигурных скобок может быть любое выражение (в т.ч. лямбда или замыкание), которое возвращает какое-то значение, которое можно привести к строке.

    Пример:

    def factorial(n) { n == 1 ? 1 : n * factorial(n - 1) }
    def n = 11

    println "This is factorial of $n = ${factorial(n)}"

    Output:

    This is factorial of 11 = 39916800

    ОтветитьУдалить