многострочное регулярное выражение не работает в ruby

#regex #ruby

#регулярное выражение #ruby

Вопрос:

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

Я использую %r{}x формат для его использования в многострочном режиме, но он не работает.

 regex = (/A(RM|R1)([A-Z])([A-Z])(d )(dd )([A-Z])([A-Z])([A-Z] )-?(d )([A-Z])(d)#?([A-Z])([A-Z])(d)z/)
 

в одной строке

 regex = %r{
        ([A-Z])
        ([A-Z])
        ([A-Z])
        (d )
        (dd )
        ([A-Z])
        ([A-Z])
        ([A-Z] )
        -?
        (d )
        ([A-Z])
        (d)
        #?
        ([A-Z])
        ([A-Z])
        (d)
     }x
 

в нескольких строках (по одной группе в каждой строке)

Что не так с моим подходом?

Ответ №1:

Вы должны экранировать # символ, как в режиме свободного пробела, он обозначает начало комментария:

Буквенный пробел внутри шаблона игнорируется, а символ octothorpe ( # ) вводит комментарий до конца строки. Это позволяет организовать компоненты шаблона потенциально более удобным для чтения способом.

Итак, замените #? на #? .

Ответ №2:

Вот ваше регулярное выражение, определенное в режиме свободного пробела, и это то, что, я думаю, вы ищете.

 regex = /
        A        # beginning of string
        (RM|R1)   # match 'RM' or 'R1'           CG  1 
        ([A-Z])   # match 1 uppercase letter     CG  2
        ([A-Z])   # match 1 uppercase letter     CG  3
        (d )     # match > 0 digits             CG  4
        (d{2,})  # match > 0 digits             CG  5
        ([A-Z])   # match 1 uppercase letter     CG  6
        ([A-Z])   # match 1 uppercase letter     CG  7
        ([A-Z] )  # match > 0 uppercase letters  CG  8
        -?        # optionally match '-'
        (d )     # match > 0 digits             CG  9
        ([A-Z])   # match 1 uppercase letter     CG 10
        (d)      # match > 0 digits             CG 11
        #?       # optionally match '#'
        ([A-Z])   # match 1 uppercase letter     CG 12
        ([A-Z])   # match 1 uppercase letter     CG 13
        (d)      # match > 0 digits             CG 14
        z        # end of string
        /x        # free-spacing regex definition mode
 

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

Я внес два изменения в ваше регулярное выражение. Во-первых, я заменил (dd ) на (d{2,}) , который имеет тот же эффект, но, возможно, читается лучше. Во-вторых, символ "#" начинает комментарий в режиме свободного интервала, поэтому он должен быть экранирован ( # ), если он должен быть сопоставлен.

В качестве примера использования этого регулярного выражения,

 test_str = "RMAB12345CDEF-6G7#HI8"
m = test_str.match regex
  #=> #<MatchData "RMAB12345CDEF-6G7#HI8" 1:"RM" 2:"A" 3:"B" 4:"123" 5:"45"
  #     6:"C" 7:"D" 8:"EF" 9:"6" 10:"G" 11:"7" 12:"H" 13:"I" 14:"8"> 
m.captures
  #=> ["RM", "A", "B", "123", "45", "C", "D", "EF", "6", "G", "7", "H", "I", "8"] 
 

Обратите внимание, что неясно, как 5 цифр должны быть разделены между группами захвата 4 и 5.

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

 "ab c".match? /ab c/   #=> true
"ab c".match? /ab c/x  #=> false
"abc".match?  /ab c/x  #=> true
 

Вот несколько способов защитить символ пробела (все возвращаемые true ):

 "ab c".match? /ab[ ]c/x          # put in a character class
"ab c".match? /ab[[:space:]]c/x  # Unicode bracket expression 
"ab c".match? /abp{Space}c/x    # Unicode p{} construct
"ab c".match? /absc/x           # match a whitespace character
 

Обратите внимание, что s соответствует табуляции, новой строке и двум другим символам, а также пробелам, которые могут быть или не быть желательными.