Spec-Zone.ru › Ruby 2.6

класс Regexp

Родитель:
Объект

A Regexp хранит регулярное выражение, используемое для сопоставления шаблона со строками. Регулярные выражения создаются с помощью литералов /.../ и %r{...}, а также с помощью конструктора Regexp::new.

Регулярные выражения (regexp) — это шаблоны, описывающие содержимое строки. Они используются для проверки наличия заданного шаблона в строке или для извлечения совпадающих частей. Они создаются с помощью литералов /pat/ и %r{pat} или с помощью конструктора Regexp.new.

Регулярное выражение обычно ограничено с помощью слэшей (/). Например:

/hay/ =~ 'haystack'   #=> 0
/y/.match('haystack') #=> #<MatchData "y">

Если строка содержит шаблон, то она считается совпадающей. Литеральная строка совпадает сама с собой.

Здесь 'стог сена' не содержит шаблон 'игла', поэтому он не совпадает:

/needle/.match('haystack') #=> nil

Здесь 'стог сена' содержит шаблон 'стог', поэтому он совпадает:

/hay/.match('haystack')    #=> #<MatchData "hay">

В частности, /st/ требует, чтобы строка содержала букву s, за которой следует буква t, поэтому она также совпадает с стог сена.

=~ и Regexp#match

Сопоставление шаблонов можно выполнить, используя оператор =~ или метод Regexp#match.

=~ оператор

=~ — базовый оператор сопоставления шаблонов в Ruby. Когда один операнд является регулярным выражением, а другой — строкой, то регулярное выражение используется в качестве шаблона для сопоставления со строкой. (Этот оператор эквивалентно определен Regexp и String, поэтому порядок String и Regexp не имеет значения. Другие классы могут иметь другие реализации =~.) Если совпадение найдено, оператор возвращает индекс первого совпадения в строке, в противном случае он возвращает nil.

/hay/ =~ 'haystack'   #=> 0
'haystack' =~ /hay/   #=> 0
/a/   =~ 'haystack'   #=> 1
/u/   =~ 'haystack'   #=> nil

Использование оператора =~ с String и Regexp устанавливает глобальную переменную $~ после успешного совпадения. $~ содержит объект MatchData. Regexp.last_match эквивалентно $~.

Regexp#match метод

Метод match возвращает объект MatchData:

/st/.match('haystack')   #=> #<MatchData "st">

Метасимволы и экранирование

Следующие являются метасимволами (, ), [, ], {, }, ., ?, +, *. Они имеют определенный смысл, когда появляются в шаблоне. Для их буквального сопоставления они должны быть экранированы с помощью обратного слэша. Чтобы буквально сопоставить обратный слэш, экранируйте его с помощью обратного слэша: \\.

/1 \+ 2 = 3\?/.match('Does 1 + 2 = 3?') #=> #<MatchData "1 + 2 = 3?">
/a\\\\b/.match('a\\\\b')                    #=> #<MatchData "a\\b">

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

/\s\u{6771 4eac 90fd}/.match("Go to 東京都")
    #=> #<MatchData " 東京都">

Произвольные выражения Ruby могут быть встроены в шаблоны с помощью конструкции #{...}.

place = "東京都"
/#{place}/.match("Go to 東京都")
    #=> #<MatchData "東京都">

Классы символов

Класс символов ограничен квадратными скобками ([, ]) и содержит символы, которые могут появиться в этом месте совпадения. /[ab]/ означает a или b, в отличие от /ab/, которое означает a, за которым следует b.

/W[aeiou]rd/.match("Word") #=> #<MatchData "Word">

Внутри класса символов дефис (-) — метасимвол, обозначающий интервал символов включительно. [abcd] эквивалентно [a-d]. Диапазон может следовать за другим диапазоном, поэтому [abcdwxyz] эквивалентно [a-dw-z]. Порядок появления диапазонов или отдельных символов внутри класса символов не имеет значения.

/[0-9a-f]/.match('9f') #=> #<MatchData "9">
/[9f]/.match('9f')     #=> #<MatchData "9">

Если первый символ класса символов — это каретка (^), класс инвертируется: он сопоставляется с любым символом кроме названных.

/[^a-eg-z]/.match('f') #=> #<MatchData "f">

Класс символов может содержать другой класс символов. Сам по себе это не полезно, потому что [a-z[0-9]] описывает тот же набор, что и [a-z0-9]. Однако классы символов также поддерживают оператор &&, который выполняет пересечение множеств своих аргументов. Их можно объединить следующим образом:

/[a-w&&[^c-g]z]/ # ([a-w] AND ([^c-g] OR z))

Это эквивалентно:

/[abh-w]/

Следующие метасимволы также ведут себя как классы символов:

  • /./ - Любой символ, кроме новой строки.

  • /./m - Любой символ (модификатор m включает многострочный режим)

  • /\w/ - Символ слова ([a-zA-Z0-9_])

  • /\W/ - Символ, не являющийся словом ([^a-zA-Z0-9_]). Обратитесь к Bug #4044, если используете /\W/ с модификатором /i.

  • /\d/ - Цифровой символ ([0-9])

  • /\D/ - Символ, не являющийся цифрой ([^0-9])

  • /\h/ - Символ шестнадцатеричной цифры ([0-9a-fA-F])

  • /\H/ - Символ, не являющийся шестнадцатеричной цифрой ([^0-9a-fA-F])

  • /\s/ - Символ пробела: /[ \t\r\n\f\v]/

  • /\S/ - Символ, не являющийся пробелом: /[^ \t\r\n\f\v]/

POSIX выражения в скобках также аналогичны классам символов. Они предлагают портативную альтернативу вышесказанному с дополнительным преимуществом, заключающимся в том, что они охватывают не-ASCII символы. Например, /\d/ сопоставляет только ASCII десятичные цифры (0-9); в то время как /[[:digit:]]/ сопоставляет любой символ в категории Unicode Nd.

  • /[[:alnum:]]/ - Буквенно-цифровой символ

  • /[[:alpha:]]/ - Буквенный символ

  • /[[:blank:]]/ - Пробел или табуляция

  • /[[:cntrl:]]/ - Управляющий символ

  • /[[:digit:]]/ - Цифра

  • /[[:graph:]]/ - Символ, не являющийся пробелом (исключает пробелы, управляющие символы и т. п.)

  • /[[:lower:]]/ - Символ строчной буквы

  • /[[:print:]]/ - Как [:graph:], но включает символ пробела

  • /[[:punct:]]/ - Символ пунктуации

  • /[[:space:]]/ - Символ пробела ([:blank:], новая строка, возврат каретки и т. д.)

  • /[[:upper:]]/ - Символ заглавной буквы

  • /[[:xdigit:]]/ - Цифра, допустимая в шестнадцатеричном числе (т. е., 0-9a-fA-F)

Ruby также поддерживает следующие не-POSIX классы символов:

  • /[[:word:]]/ - Символ в одной из следующих категорий Unicode: Буква, Маркер, Число, Разделительная пунктуация

  • /[[:ascii:]]/ - Символ в ASCII наборе символов

    # U+06F2 is "EXTENDED ARABIC-INDIC DIGIT TWO"
    /[[:digit:]]/.match("\u06F2")    #=> #<MatchData "\u{06F2}">
    /[[:upper:]][[:lower:]]/.match("Hello") #=> #<MatchData "He">
    /[[:xdigit:]][[:xdigit:]]/.match("A6")  #=> #<MatchData "A6">
    

Повторение

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

  • * - Ноль или более раз

  • + - Один или более раз

  • ? - Ноль или один раз (опционально)

  • {n} - Ровно n раз

  • {n,} - n или более раз

  • {,m} - m или меньше раз

  • {n,m} - Не менее n и не более m раз

По крайней мере одна заглавная буква ('H'), по крайней мере одна строчная буква ('e'), две буквы 'l', затем одна буква 'o':

"Hello".match(/[[:upper:]]+[[:lower:]]+l{2}o/) #=> #<MatchData "Hello">

По умолчанию повторение является жадным: сопоставляется как можно больше вхождений, при условии, что общее совпадение все еще возможно. В противоположность этому, ленивое сопоставление делает минимальное количество совпадений, необходимое для общего успеха. Жадный метасимвол может быть сделан ленивым, добавив за ним ?.

Оба шаблона ниже соответствуют строке. Первый использует жадный квантификатор, поэтому '.+' сопоставляет '<a><b>'; второй использует ленивый квантификатор, поэтому '.+?' сопоставляет '<a>':

/<.+>/.match("<a><b>")  #=> #<MatchData "<a><b>">
/<.+?>/.match("<a><b>") #=> #<MatchData "<a>">

Квантификатор, за которым следует +, сопоставляется поглощающе: после сопоставления он не возвращается. Они ведут себя как жадные квантификаторы, но после сопоставления отказываются «отказаться» от своего совпадения, даже если это ставит под угрозу общее совпадение.

Захват

Скобки могут использоваться для захвата. Текст, заключенный в n<sup>th</sup> группу скобок, может быть впоследствии сослаться на n. Внутри шаблона используйте ссылку назад \n; вне шаблона используйте MatchData[n].

'at' захватывается первой группой скобок, а затем ссылается на неё позже с помощью \1:

/[csh](..) [csh]\1 in/.match("The cat sat in the hat")
    #=> #<MatchData "cat sat in" 1:"at">

Regexp#match возвращает объект MatchData, который делает доступным захваченный текст с помощью метода []:

/[csh](..) [csh]\1 in/.match("The cat sat in the hat")[1] #=> 'at'

К группам захвата можно обращаться по имени, определённым с помощью конструкций (?<name>) или (?'name').

/\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")
    #=> #<MatchData "$3.67" dollars:"3" cents:"67">
/\$(?<dollars>\d+)\.(?<cents>\d+)/.match("$3.67")[:dollars] #=> "3"

Имена групп можно ссылаться с помощью \k<name>, где name — имя группы.

/(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy')
    #=> #<MatchData "ototo" vowel:"o">

Примечание: Регулярное выражение не может одновременно использовать именованные ссылки назад и пронумерованные ссылки назад.

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

/\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ "$3.67" #=> 0
dollars #=> "3"

Группирование

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

Шаблон ниже соответствует гласной, за которой следуют 2 символа слова:

/[aeiou]\w{2}/.match("Caenorhabditis elegans") #=> #<MatchData "aen">

В то время как следующий шаблон соответствует гласной, за которой следует символ слова дважды, то есть [aeiou]\w[aeiou]\w: 'enor'.

/([aeiou]\w){2}/.match("Caenorhabditis elegans")
    #=> #<MatchData "enor" 1:"or">

Конструкции (?:…) обеспечивают группирование без захвата. То есть, она объединяет содержащиеся в ней термины в атомарное целое без создания обратной ссылки. Это выгодно для производительности за счет небольшого снижения читабельности.

Первая группа скобок захватывает 'n', а вторая — 'ti'. Вторая группа ссылается позже с обратной ссылкой \2:

/I(n)ves(ti)ga\2ons/.match("Investigations")
    #=> #<MatchData "Investigations" 1:"n" 2:"ti">

Первая группа скобок теперь сделана незахватывающей с помощью '?:', поэтому она по-прежнему соответствует 'n', но не создает обратной ссылки. Таким образом, обратная ссылка \1 теперь относится к 'ti'.

/I(?:n)ves(ti)ga\1ons/.match("Investigations")
    #=> #<MatchData "Investigations" 1:"ti">

Атомарная группировка

Группирование может быть сделано атомарным с помощью (?>pat). Это заставляет подвыражение pat соответствовать независимо от остальной части выражения таким образом, что то, что оно соответствует, фиксируется для остальной части соответствия, если весь подвыражение не должно быть оставлено и впоследствии пересмотрено. Таким образом, pat обрабатывается как неделимое целое. Атомарная группировка обычно используется для оптимизации шаблонов, чтобы предотвратить бесполезное обратное отслеживание движка регулярных выражений.

" в шаблоне ниже соответствует первой букве строки, затем .* соответствует Quote“. Это приводит к тому, что общее соответствие терпит неудачу, поэтому текст, соответствующий .*, отслеживается на одну позицию назад, что оставляет последний символ строки доступным для соответствия "

/".*"/.match('"Quote"')     #=> #<MatchData "\"Quote\"">

Если .* сгруппирована атомарно, она откажется от отслеживания Quote“, даже если это означает, что общее соответствие терпит неудачу

/"(?>.*)"/.match('"Quote"') #=> nil

Вызовы подвыражений

Синтаксис \g<name> соответствует предыдущему подвыражению с именем name, которое может быть именем или номером группы, еще раз. Это отличается от обратных ссылок тем, что оно повторно выполняет группу, а не просто пытается повторно сопоставить тот же текст.

Этот шаблон соответствует символу ( и присваивает его группе paren, пытается вызвать это подвыражение paren снова, но терпит неудачу, а затем соответствует литералу ):

/\A(?<paren>\(\g<paren>*\))*\z/ =~ '()'

/\A(?<paren>\(\g<paren>*\))*\z/ =~ '(())' #=> 0
# ^1
#      ^2
#           ^3
#                 ^4
#      ^5
#           ^6
#                      ^7
#                       ^8
#                       ^9
#                           ^10
  1. Соответствует в начале строки, то есть перед первым символом.

  2. Входит в именованную группу захвата под названием paren

  3. Соответствует литералу (, первому символу в строке

  4. Вызывает группу paren снова, то есть рекурсивно возвращается к второму шагу

  5. Повторно входит в группу paren

  6. Соответствует литералу (, второму символу в строке

  7. Попытаться вызвать paren в третий раз, но потерпит неудачу, потому что это предотвратит успешное соответствие в целом

  8. Сопоставляем литерал ), третий символ в строке. Помечаем конец второго рекурсивного вызова

  9. Соответствует литералу ), четвертый символ в строке

  10. Сопоставляем конец строки

Альтернация

Метасимвол вертикальной черты (|) объединяет два выражения в одно, которое соответствует любому из выражений. Каждое выражение является альтернативой.

/\w(and|or)\w/.match("Feliformia") #=> #<MatchData "form" 1:"or">
/\w(and|or)\w/.match("furandi")    #=> #<MatchData "randi" 1:"and">
/\w(and|or)\w/.match("dissemblance") #=> nil

Свойства символов

Конструкции \p{} соответствуют символам с указанным свойством, подобно POSIX-скобочным классам.

  • /\p{Alnum}/ - Буквенно-цифровой символ

  • /\p{Alpha}/ - Буквенный символ

  • /\p{Blank}/ - Пробел или табуляция

  • /\p{Cntrl}/ - Символ управления

  • /\p{Digit}/ - Цифра

  • /\p{Graph}/ - Символ, не являющийся пробелом (исключает пробелы, управляющие символы и аналогичные)

  • /\p{Lower}/ - Строчный буквенный символ

  • /\p{Print}/ - Как \p{Graph}, но включает символ пробела

  • /\p{Punct}/ - Символ пунктуации

  • /\p{Space}/ - Символ пробела ([:blank:], перевод строки, возврат каретки и т.д.)

  • /\p{Upper}/ - Прописной буквенный символ

  • /\p{XDigit}/ - Цифра, допускаемая в шестнадцатеричном числе (то есть, 0-9a-fA-F)

  • /\p{Word}/ - Элемент одной из следующих общих категорий Unicode: Letter, Mark, Number, Connector_Punctuation

  • /\p{ASCII}/ - Символ набора символов ASCII

  • /\p{Any}/ - Любой символ Unicode (включая неназначенные символы)

  • /\p{Assigned}/ - Назначенный символ

Значение Общей категории символа Unicode также можно сопоставить с помощью \p{Ab}, где Ab - сокращение категории, как описано ниже:

  • /\p{L}/ - 'Letter'

  • /\p{Ll}/ - 'Letter: Lowercase'

  • /\p{Lm}/ - 'Letter: Mark'

  • /\p{Lo}/ - 'Letter: Other'

  • /\p{Lt}/ - 'Letter: Titlecase'

  • /\p{Lu}/ - 'Letter: Uppercase

  • /\p{Lo}/ - 'Letter: Other'

  • /\p{M}/ - 'Mark'

  • /\p{Mn}/ - 'Mark: Nonspacing'

  • /\p{Mc}/ - 'Mark: Spacing Combining'

  • /\p{Me}/ - 'Mark: Enclosing'

  • /\p{N}/ - 'Number'

  • /\p{Nd}/ - 'Number: Decimal Digit'

  • /\p{Nl}/ - 'Number: Letter'

  • /\p{No}/ - 'Number: Other'

  • /\p{P}/ - 'Punctuation'

  • /\p{Pc}/ - 'Punctuation: Connector'

  • /\p{Pd}/ - 'Punctuation: Dash'

  • /\p{Ps}/ - 'Punctuation: Open'

  • /\p{Pe}/ - 'Punctuation: Close'

  • /\p{Pi}/ - 'Punctuation: Initial Quote'

  • /\p{Pf}/ - 'Punctuation: Final Quote'

  • /\p{Po}/ - 'Punctuation: Other'

  • /\p{S}/ - 'Symbol'

  • /\p{Sm}/ - 'Symbol: Math'

  • /\p{Sc}/ - 'Symbol: Currency'

  • /\p{Sc}/ - 'Symbol: Currency'

  • /\p{Sk}/ - 'Symbol: Modifier'

  • /\p{So}/ - 'Symbol: Other'

  • /\p{Z}/ - 'Separator'

  • /\p{Zs}/ - 'Separator: Space'

  • /\p{Zl}/ - 'Separator: Line'

  • /\p{Zp}/ - 'Separator: Paragraph'

  • /\p{C}/ - 'Other'

  • /\p{Cc}/ - 'Other: Control'

  • /\p{Cf}/ - 'Other: Format'

  • /\p{Cn}/ - 'Other: Not Assigned'

  • /\p{Co}/ - 'Other: Private Use'

  • /\p{Cs}/ - 'Other: Surrogate'

Наконец, \p{} соответствует скрипту символа Unicode. Поддерживаются следующие скрипты: Arabic, Armenian, Balinese, Bengali, Bopomofo, Braille, Buginese, Buhid, Canadian_Aboriginal, Carian, Cham, Cherokee, Common, Coptic, Cuneiform, Cypriot, Cyrillic, Deseret, Devanagari, Ethiopic, Georgian, Glagolitic, Gothic, Greek, Gujarati, Gurmukhi, Han, Hangul, Hanunoo, Hebrew, Hiragana, Inherited, Kannada, Katakana, Kayah_Li, Kharoshthi, Khmer, Lao, Latin, Lepcha, Limbu, Linear_B, Lycian, Lydian, Malayalam, Mongolian, Myanmar, New_Tai_Lue, Nko, Ogham, Ol_Chiki, Old_Italic, Old_Persian, Oriya, Osmanya, Phags_Pa, Phoenician, Rejang, Runic, Saurashtra, Shavian, Sinhala, Sundanese, Syloti_Nagri, Syriac, Tagalog, Tagbanwa, Tai_Le, Tamil, Telugu, Thaana, Thai, Tibetan, Tifinagh, Ugaritic, Vai и Yi.

Код символа Unicode U+06E9 называется «ARABIC PLACE OF SAJDAH» и принадлежит арабскому письму:

/\p{Arabic}/.match("\u06E9") #=> #<MatchData "\u06E9">

Все свойства символов могут быть инвертированы путем добавления символа в начале их имени (^).

Буква 'A' не входит в категорию Unicode Ll (Letter; Lowercase), поэтому это соответствие успешно:

/\p{^Ll}/.match("A") #=> #<MatchData "A">

Якоря

Якоря — метасимволы, которые соответствуют нулевым позициям между символами, закрепляя соответствие к определенной позиции.

  • ^ - Совпадение начала строки

  • $ - Совпадение конца строки

  • \A - Совпадение начала строки.

  • \Z - Совпадение конца строки. Если строка заканчивается новой строкой, совпадение происходит перед новой строкой

  • \z - Совпадение конца строки

  • \G - Совпадение с первой позицией совпадения:

    В методах типа String#gsub и String#scan оно меняется на каждой итерации. Изначально оно совпадает с началом темы, а на каждой последующей итерации - с местом окончания последнего совпадения.

    "    a b c".gsub(/ /, '_')    #=> "____a_b_c"
    "    a b c".gsub(/\G /, '_')  #=> "____a b c"
    

    В методах типа Regexp#match и String#match, которые принимают (необязательный) смещение, оно совпадает с началом поиска.

    "hello, world".match(/,/, 3)    #=> #<MatchData ",">
    "hello, world".match(/\G,/, 3)  #=> nil
    
  • \b - Совпадение границ слов вне скобок; возврат (0x08) внутри скобок

  • \B - Совпадение границ неслов

  • (?=pat) - Положительное просмотр вперед утверждение: гарантирует, что следующие символы соответствуют pat, но не включает эти символы в сопоставляемый текст

  • (?!pat) - Отрицательное просмотр вперед утверждение: гарантирует, что следующие символы не соответствуют pat, но не включает эти символы в сопоставляемый текст

  • (?<=pat) - Положительное просмотр назад утверждение: гарантирует, что предыдущие символы соответствуют pat, но не включает эти символы в сопоставляемый текст

  • (?<!pat) - Отрицательное просмотр назад утверждение: гарантирует, что предыдущие символы не соответствуют pat, но не включает эти символы в сопоставляемый текст

Если шаблон не привязан, он может начинаться в любой точке строки:

/real/.match("surrealist") #=> #<MatchData "real">

Привязка шаблона к началу строки заставляет совпадение начинаться там. 'real' не встречается в начале строки, поэтому совпадение не происходит:

/\Areal/.match("surrealist") #=> nil

Нижеприведенное совпадение не происходит, потому что, хотя 'Demand' содержит 'and', шаблон не встречается на границе слова.

/\band/.match("Demand")

В то время как в следующем примере 'and' привязан к границе неслова, поэтому вместо совпадения с первым 'and' он совпадает с четвертым символом 'demand':

/\Band.+/.match("Supply and demand curve") #=> #<MatchData "and curve">

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

/(?<=<b>)\w+(?=<\/b>)/.match("Fortune favours the <b>bold</b>")
    #=> #<MatchData "bold">

Параметры

Заключающий разделитель для regexp может быть последован одним или несколькими однобуквенными параметрами, которые управляют тем, как шаблон может соответствовать.

  • /pat/i - Игнорировать регистр

  • /pat/m - Рассматривать новую строку как символ, сопоставленный .

  • /pat/x - Игнорировать пробелы и комментарии в шаблоне

  • /pat/o - Выполнить интерполяцию #{} только один раз

i, m и x также могут применяться к подвыражениям с помощью конструкции (?on-off), которая включает параметры on и отключает параметры off для выражения, заключенного в скобки:

/a(?i:b)c/.match('aBc')   #=> #<MatchData "aBc">
/a(?-i:b)c/i.match('ABC') #=> nil

Кроме того, эти параметры также могут быть переключены для остальной части шаблона:

/a(?i)bc/.match('abC') #=> #<MatchData "abC">

Параметры также могут быть использованы с Regexp.new:

Regexp.new("abc", Regexp::IGNORECASE)                     #=> /abc/i
Regexp.new("abc", Regexp::MULTILINE)                      #=> /abc/m
Regexp.new("abc # Comment", Regexp::EXTENDED)             #=> /abc # Comment/x
Regexp.new("abc", Regexp::IGNORECASE | Regexp::MULTILINE) #=> /abc/mi

Режим свободного форматирования и комментарии

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

Шаблон, созданный для сопоставления числа с необязательными десятичными знаками:

float_pat = /\A
    [[:digit:]]+ # 1 or more digits before the decimal point
    (\.          # Decimal point
        [[:digit:]]+ # 1 or more digits after the decimal point
    )? # The decimal point and following digits are optional
\Z/x
float_pat.match('3.14') #=> #<MatchData "3.14" 1:".14">

Существует ряд стратегий для сопоставления пробелов:

  • Используйте шаблон, такой как \s или \p{Space}.

  • Используйте экранированные пробелы, такие как \ , т.е. пробел, предшествующий обратной косой черте.

  • Используйте класс символов, такой как [ ].

Комментарии могут быть включены в шаблон, не являющийся x, с помощью конструкции (?#comment), где comment — произвольный текст, игнорируемый движком regexp.

Комментарии в литералах regexp не могут включать экранированные символы-разделители.

Encoding

Предполагается, что регулярные выражения используют кодировку источника. Это можно изменить с помощью одного из следующих модификаторов.

  • /pat/u - UTF-8

  • /pat/e - EUC-JP

  • /pat/s - Windows-31J

  • /pat/n - ASCII-8BIT

Regexp может быть сопоставлен со строкой, если они используют одну кодировку или кодировка regexp — US-ASCII, а кодировка строки — совместима с ASCII.

Если попытка сопоставления между несовместимыми кодировками происходит, возникает исключение Encoding::CompatibilityError.

Предикат Regexp#fixed_encoding? указывает, имеет ли regexp фиксированную кодировку, т. е. несовместимую с ASCII. Кодировку regexp можно явно зафиксировать, передав Regexp::FIXEDENCODING в качестве второго аргумента Regexp.new:

r = Regexp.new("a".force_encoding("iso-8859-1"),Regexp::FIXEDENCODING)
r =~ "a\u3042"
   # raises Encoding::CompatibilityError: incompatible encoding regexp match
   #         (ISO-8859-1 regexp with UTF-8 string)

Специальные глобальные переменные

Сопоставление шаблонов устанавливает некоторые глобальные переменные:

  • $~ эквивалентно Regexp.last_match;

  • $& содержит весь сопоставленный текст;

  • $` содержит строку перед совпадением;

  • $' содержит строку после совпадения;

  • $1, $2 и т. д. содержат текст, соответствующий первой, второй и т. д. группе захвата;

  • $+ содержит последнюю группу захвата.

Пример:

m = /s(\w{2}).*(c)/.match('haystack') #=> #<MatchData "stac" 1:"ta" 2:"c">
$~                                    #=> #<MatchData "stac" 1:"ta" 2:"c">
Regexp.last_match                     #=> #<MatchData "stac" 1:"ta" 2:"c">

$&      #=> "stac"
        # same as m[0]
$`      #=> "hay"
        # same as m.pre_match
$'      #=> "k"
        # same as m.post_match
$1      #=> "ta"
        # same as m[1]
$2      #=> "c"
        # same as m[2]
$3      #=> nil
        # no third group in pattern
$+      #=> "c"
        # same as m[-1]

Эти глобальные переменные являются локальными переменными потока и метода.

Производительность

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

Рассмотрим строку из 25 a, d, 4 a и c.

s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
#=> "aaaaaaaaaaaaaaaaaaaaaaaaadaaaac"

Следующие шаблоны сопоставляются мгновенно, как ожидалось:

s = 'a' * 25 + 'd' + 'a' * 4 + 'c'
#=> "aaaaaaaaaaaaaaaaaaaaaaaaadaaaac"

Однако следующий шаблон требует значительно больше времени:

/(b|a+)*c/ =~ s #=> 26

Это происходит потому, что атом в regexp квантифицируется как непосредственным +, так и окружающим *, без разницы, какой из них контролирует конкретный символ. Результирующая недетерминированность приводит к производительности сверхлинейного порядка. (См. Mastering Regular Expressions (3-е изд.), стр. 222, by Jeffery Friedl, для глубокого анализа). Этот конкретный случай можно исправить с помощью атомарной группировки, которая предотвращает ненужный возврат:

(start = Time.now) && /(b|a+)*c/ =~ s && (Time.now - start)
   #=> 24.702736882
(start = Time.now) && /(?>b|a+)*c/ =~ s && (Time.now - start)
   #=> 0.000166571

Аналогичный случай демонстрируется следующим примером, который на моём компьютере занимает около 60 секунд для выполнения:

Сопоставление строки из 29 a с шаблоном из 29 необязательных a, за которыми следуют 29 обязательных a:

Regexp.new('a?' * 29 + 'a' * 29) =~ 'a' * 29

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

Лучший способ улучшить производительность — значительно уменьшить количество необходимых обратных действий. В данном случае вместо отдельного соответствия 29 необязательным a можно сразу сопоставить диапазон необязательных a с помощью a{0,29}:

Regexp.new('a{0,29}' + 'a' * 29) =~ 'a' * 29

Константы

EXTENDED

см. Regexp.options и Regexp.new

FIXEDENCODING

см. Regexp.options и Regexp.new

IGNORECASE

см. Regexp.options и Regexp.new

MULTILINE

см. Regexp.options и Regexp.new

NOENCODING

см. Regexp.options и Regexp.new

Методы публичного класса

compile(*args)

Псевдоним для Regexp.new

escape(str) → string Показать исходный код
static VALUE
rb_reg_s_quote(VALUE c, VALUE str)
{
    return rb_reg_quote(reg_operand(str, TRUE));
}

Экранирует любые символы, которые имели бы специальное значение в регулярном выражении. Возвращает новую экранированную строку или self, если никакие символы не были экранированы. Для любой строки Regexp.new(Regexp.escape(str))=~str будет истинно.

Regexp.escape('\*?{}.')   #=> \\\*\?\{\}\.
json_create(object) Показать исходный код
# File ext/json/lib/json/add/regexp.rb, line 11
def self.json_create(object)
  new(object['s'], object['o'])
end

Десериализует JSON строку, создавая новый объект Regexp с исходным s (Regexp или String) и параметрами o, сериализованными to_json

last_match → matchdata Показать исходный код
last_match(n) → str
static VALUE
rb_reg_s_last_match(int argc, VALUE *argv)
{
    if (rb_check_arity(argc, 0, 1) == 1) {
        VALUE match = rb_backref_get();
        int n;
        if (NIL_P(match)) return Qnil;
        n = match_backref_number(match, argv[0]);
        return rb_reg_nth_match(n, match);
    }
    return match_getter();
}

Первый вариант возвращает объект MatchData, сгенерированный последним успешным соответствием шаблона. Эквивалентно чтению специальной глобальной переменной $~ (см. Специальные глобальные переменные в Regexp для получения подробностей).

Второй вариант возвращает n-е поле в этом объекте MatchData. n может быть строкой или символом для ссылки на именованный захват.

Обратите внимание, что last_match является локальным для потока и области метода, который выполнил соответствие шаблона.

/c(.)t/ =~ 'cat'        #=> 0
Regexp.last_match       #=> #<MatchData "cat" 1:"a">
Regexp.last_match(0)    #=> "cat"
Regexp.last_match(1)    #=> "a"
Regexp.last_match(2)    #=> nil

/(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ =~ "var = val"
Regexp.last_match       #=> #<MatchData "var = val" lhs:"var" rhs:"val">
Regexp.last_match(:lhs) #=> "var"
Regexp.last_match(:rhs) #=> "val"
new(string, [options]) → regexp Показать исходный код
new(regexp) → regexp
compile(string, [options]) → regexp
compile(regexp) → regexp
static VALUE
rb_reg_initialize_m(int argc, VALUE *argv, VALUE self)
{
    int flags = 0;
    VALUE str;
    rb_encoding *enc = 0;

    rb_check_arity(argc, 1, 3);
    if (RB_TYPE_P(argv[0], T_REGEXP)) {
        VALUE re = argv[0];

        if (argc > 1) {
            rb_warn("flags ignored");
        }
        rb_reg_check(re);
        flags = rb_reg_options(re);
        str = RREGEXP_SRC(re);
    }
    else {
        if (argc >= 2) {
            if (FIXNUM_P(argv[1])) flags = FIX2INT(argv[1]);
            else if (RTEST(argv[1])) flags = ONIG_OPTION_IGNORECASE;
        }
        if (argc == 3 && !NIL_P(argv[2])) {
            char *kcode = StringValuePtr(argv[2]);
            if (kcode[0] == 'n' || kcode[0] == 'N') {
                enc = rb_ascii8bit_encoding();
                flags |= ARG_ENCODING_NONE;
            }
            else {
                rb_warn("encoding option is ignored - %s", kcode);
            }
        }
        str = StringValue(argv[0]);
    }
    if (enc && rb_enc_get(str) != enc)
        rb_reg_init_str_enc(self, str, enc, flags);
    else
        rb_reg_init_str(self, str, flags);
    return self;
}

Создает новое регулярное выражение из pattern, которое может быть либо String, либо Regexp (в этом случае параметры этого regexp'a распространяются), и новые параметры могут не быть указаны (изменение, начиная с Ruby 1.8).

Если options является Integer, это должно быть одно или несколько из констант Regexp::EXTENDED, Regexp::IGNORECASE и Regexp::MULTILINE, объединенные операцией побитового ИЛИ.

В противном случае, если options не является nil или false, regexp будет регистронезависимым.

r1 = Regexp.new('^a-z+:\\s+\w+') #=> /^a-z+:\s+\w+/
r2 = Regexp.new('cat', true)     #=> /cat/i
r3 = Regexp.new(r2)              #=> /cat/i
r4 = Regexp.new('dog', Regexp::EXTENDED | Regexp::IGNORECASE) #=> /dog/ix
quote(str) → string Показать исходный код
static VALUE
rb_reg_s_quote(VALUE c, VALUE str)
{
    return rb_reg_quote(reg_operand(str, TRUE));
}

Экранирует любые символы, которые имели бы специальное значение в регулярном выражении. Возвращает новую экранированную строку или self, если никакие символы не были экранированы. Для любой строки Regexp.new(Regexp.escape(str))=~str будет истинно.

Regexp.escape('\*?{}.')   #=> \\\*\?\{\}\.
try_convert(obj) → re or nil Показать исходный код
static VALUE
rb_reg_s_try_convert(VALUE dummy, VALUE re)
{
    return rb_check_regexp_type(re);
}

Попытка преобразовать obj в Regexp, используя метод to_regexp. Возвращает преобразованный regexp или nil, если obj не может быть преобразован по какой-либо причине.

Regexp.try_convert(/re/)         #=> /re/
Regexp.try_convert("re")         #=> nil

o = Object.new
Regexp.try_convert(o)            #=> nil
def o.to_regexp() /foo/ end
Regexp.try_convert(o)            #=> /foo/
union(pat1, pat2, ...) → new_regexp Показать исходный код
union(pats_ary) → new_regexp
static VALUE
rb_reg_s_union_m(VALUE self, VALUE args)
{
    VALUE v;
    if (RARRAY_LEN(args) == 1 &&
        !NIL_P(v = rb_check_array_type(rb_ary_entry(args, 0)))) {
        return rb_reg_s_union(self, v);
    }
    return rb_reg_s_union(self, args);
}

Возвращает объект Regexp, который представляет собой объединение заданных patternов, т.е. будет соответствовать любой его части. Patternы могут быть объектами Regexp, в этом случае их параметры сохраняются, или Строки. Если шаблоны не заданы, возвращает /(?!)/. Поведение не определено, если какой-либо заданный pattern содержит захват.

Regexp.union                         #=> /(?!)/
Regexp.union("penzance")             #=> /penzance/
Regexp.union("a+b*c")                #=> /a\+b\*c/
Regexp.union("skiing", "sledding")   #=> /skiing|sledding/
Regexp.union(["skiing", "sledding"]) #=> /skiing|sledding/
Regexp.union(/dogs/, /cats/i)        #=> /(?-mix:dogs)|(?i-mx:cats)/

Примечание: аргументы для ::union будут пытаться преобразовать в литерал регулярного выражения через to_regexp.

Методы публичного экземпляра

rxp == other_rxp → true или false Показать исходный код
static VALUE
rb_reg_equal(VALUE re1, VALUE re2)
{
    if (re1 == re2) return Qtrue;
    if (!RB_TYPE_P(re2, T_REGEXP)) return Qfalse;
    rb_reg_check(re1); rb_reg_check(re2);
    if (FL_TEST(re1, KCODE_FIXED) != FL_TEST(re2, KCODE_FIXED)) return Qfalse;
    if (RREGEXP_PTR(re1)->options != RREGEXP_PTR(re2)->options) return Qfalse;
    if (RREGEXP_SRC_LEN(re1) != RREGEXP_SRC_LEN(re2)) return Qfalse;
    if (ENCODING_GET(re1) != ENCODING_GET(re2)) return Qfalse;
    if (memcmp(RREGEXP_SRC_PTR(re1), RREGEXP_SRC_PTR(re2), RREGEXP_SRC_LEN(re1)) == 0) {
        return Qtrue;
    }
    return Qfalse;
}

Равенство — Два объекта RegExp равны, если их шаблоны идентичны, у них одинаковый код набора символов и их casefold? значения одинаковы.

/abc/  == /abc/x   #=> false
/abc/  == /abc/i   #=> false
/abc/  == /abc/u   #=> false
/abc/u == /abc/n   #=> false
rxp === str → true или false Показать исходный код
VALUE
rb_reg_eqq(VALUE re, VALUE str)
{
    long start;

    str = reg_operand(str, FALSE);
    if (NIL_P(str)) {
        rb_backref_set(Qnil);
        return Qfalse;
    }
    start = rb_reg_search(re, str, 0, 0);
    if (start < 0) {
        return Qfalse;
    }
    return Qtrue;
}

Равенство с учётом регистра — Используется в операторах case.

a = "HELLO"
case a
when /\A[a-z]*\z/; print "Lower case\n"
when /\A[A-Z]*\z/; print "Upper case\n"
else;              print "Mixed case\n"
end
#=> "Upper case"

Следуя за литералом регулярного выражения оператором === вы можете сравнивать с String.

/^[a-z]*$/ === "HELLO" #=> false
/^[A-Z]*$/ === "HELLO" #=> true
rxp =~ str → целое число или nil Показать исходный код
VALUE
rb_reg_match(VALUE re, VALUE str)
{
    long pos = reg_match_pos(re, &str, 0);
    if (pos < 0) return Qnil;
    pos = rb_str_sublen(str, pos);
    return LONG2FIX(pos);
}

Сопоставление — Сопоставляет rxp с str.

/at/ =~ "input data"   #=> 7
/ax/ =~ "input data"   #=> nil

Если =~ используется с литералом регулярного выражения с именованными захватами, захваченные строки (или nil) присваиваются локальным переменным, именованным именами захватов.

/(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ =~ "  x = y  "
p lhs    #=> "x"
p rhs    #=> "y"

Если соответствия нет, для переменных присваивается nil.

/(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/ =~ "  x = "
p lhs    #=> nil
p rhs    #=> nil

Это присваивание реализовано в парсере Ruby. Парсер распознаёт 'regexp-literal =~ expression' для присваивания. Регулярное выражение должно быть литералом без интерполяции и расположено в левой части.

Присваивания не происходит, если регулярное выражение не является литералом.

re = /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/
re =~ "  x = y  "
p lhs    # undefined local variable
p rhs    # undefined local variable

Интерполяция регулярного выражения, #{}, также отключает присваивание.

rhs_pat = /(?<rhs>\w+)/
/(?<lhs>\w+)\s*=\s*#{rhs_pat}/ =~ "x = y"
p lhs    # undefined local variable

Присваивание не происходит, если регулярное выражение расположено в правой части.

"  x = y  " =~ /(?<lhs>\w+)\s*=\s*(?<rhs>\w+)/
p lhs, rhs # undefined local variable
as_json(*) Показать исходный код
# File ext/json/lib/json/add/regexp.rb, line 17
def as_json(*)
  {
    JSON.create_id => self.class.name,
    'o'            => options,
    's'            => source,
  }
end

Возвращает хеш, который будет преобразован в объект JSON и представит этот объект.

casefold? → true или false Показать исходный код
static VALUE
rb_reg_casefold_p(VALUE re)
{
    rb_reg_check(re);
    if (RREGEXP_PTR(re)->options & ONIG_OPTION_IGNORECASE) return Qtrue;
    return Qfalse;
}

Возвращает значение флага игнорирования регистра.

/a/.casefold?           #=> false
/a/i.casefold?          #=> true
/(?i:a)/.casefold?      #=> false
encoding → encoding Показать исходный код
VALUE
rb_obj_encoding(VALUE obj)
{
    int idx = rb_enc_get_index(obj);
    if (idx < 0) {
	rb_raise(rb_eTypeError, "unknown encoding");
    }
    return rb_enc_from_encoding_index(idx & ENC_INDEX_MASK);
}

Возвращает объект Encoding, который представляет кодировку obj.

eql?(other_rxp) → true или false Показать исходный код
static VALUE
rb_reg_equal(VALUE re1, VALUE re2)
{
    if (re1 == re2) return Qtrue;
    if (!RB_TYPE_P(re2, T_REGEXP)) return Qfalse;
    rb_reg_check(re1); rb_reg_check(re2);
    if (FL_TEST(re1, KCODE_FIXED) != FL_TEST(re2, KCODE_FIXED)) return Qfalse;
    if (RREGEXP_PTR(re1)->options != RREGEXP_PTR(re2)->options) return Qfalse;
    if (RREGEXP_SRC_LEN(re1) != RREGEXP_SRC_LEN(re2)) return Qfalse;
    if (ENCODING_GET(re1) != ENCODING_GET(re2)) return Qfalse;
    if (memcmp(RREGEXP_SRC_PTR(re1), RREGEXP_SRC_PTR(re2), RREGEXP_SRC_LEN(re1)) == 0) {
        return Qtrue;
    }
    return Qfalse;
}

Равенство — Два объекта RegExp равны, если их шаблоны идентичны, у них одинаковый код набора символов и их casefold? значения одинаковы.

/abc/  == /abc/x   #=> false
/abc/  == /abc/i   #=> false
/abc/  == /abc/u   #=> false
/abc/u == /abc/n   #=> false
fixed_encoding? → true или false Показать исходный код
static VALUE
rb_reg_fixed_encoding_p(VALUE re)
{
    if (FL_TEST(re, KCODE_FIXED))
        return Qtrue;
    else
        return Qfalse;
}

Возвращает false, если rxp применим к строке с любой кодировкой, совместимой с ASCII. В противном случае возвращает true.

r = /a/
r.fixed_encoding?                               #=> false
r =~ "\u{6666} a"                               #=> 2
r =~ "\xa1\xa2 a".force_encoding("euc-jp")      #=> 2
r =~ "abc".force_encoding("euc-jp")             #=> 0

r = /a/u
r.fixed_encoding?                               #=> true
r.encoding                                      #=> #<Encoding:UTF-8>
r =~ "\u{6666} a"                               #=> 2
r =~ "\xa1\xa2".force_encoding("euc-jp")        #=> Encoding::CompatibilityError
r =~ "abc".force_encoding("euc-jp")             #=> 0

r = /\u{6666}/
r.fixed_encoding?                               #=> true
r.encoding                                      #=> #<Encoding:UTF-8>
r =~ "\u{6666} a"                               #=> 0
r =~ "\xa1\xa2".force_encoding("euc-jp")        #=> Encoding::CompatibilityError
r =~ "abc".force_encoding("euc-jp")             #=> nil
hash → целое число Показать исходный код
static VALUE
rb_reg_hash(VALUE re)
{
    st_index_t hashval = reg_hash(re);
    return ST2FIX(hashval);
}

Генерирует хеш на основе текста и параметров этого регулярного выражения.

См. также Object#hash.

inspect → строка Показать исходный код
static VALUE
rb_reg_inspect(VALUE re)
{
    if (!RREGEXP_PTR(re) || !RREGEXP_SRC(re) || !RREGEXP_SRC_PTR(re)) {
        return rb_any_to_s(re);
    }
    return rb_reg_desc(RREGEXP_SRC_PTR(re), RREGEXP_SRC_LEN(re), re);
}

Генерирует красиво отформатированную строку-представление объекта rxp. Неожиданно, #inspect фактически создаёт более естественную версию строки, чем #to_s.

/ab+c/ix.inspect        #=> "/ab+c/ix"
match(str) → matchdata или nil Показать исходный код
match(str,pos) → matchdata или nil
static VALUE
rb_reg_match_m(int argc, VALUE *argv, VALUE re)
{
    VALUE result, str, initpos;
    long pos;

    if (rb_scan_args(argc, argv, "11", &str, &initpos) == 2) {
        pos = NUM2LONG(initpos);
    }
    else {
        pos = 0;
    }

    pos = reg_match_pos(re, &str, pos);
    if (pos < 0) {
        rb_backref_set(Qnil);
        return Qnil;
    }
    result = rb_backref_get();
    rb_match_busy(result);
    if (!NIL_P(result) && rb_block_given_p()) {
        return rb_yield(result);
    }
    return result;
}

Возвращает объект MatchData, описывающий соответствие, или nil, если соответствия не найдено. Это эквивалентно получению значения специальной переменной $~ после обычного сопоставления. Если второй параметр присутствует, он указывает позицию в строке для начала поиска.

/(.)(.)(.)/.match("abc")[2]   #=> "b"
/(.)(.)/.match("abc", 1)[2]   #=> "c"

Если указан блок, вызовите блок с MatchData, если сопоставление успешно, чтобы вы могли написать

/M(.*)/.match("Matz") do |m|
  puts m[0]
  puts m[1]
end

вместо

if m = /M(.*)/.match("Matz")
  puts m[0]
  puts m[1]
end

В этом случае возвращаемое значение — это значение из результата выполнения блока.

match?(str) → true или false Показать исходный код
match?(str,pos) → true или false
static VALUE
rb_reg_match_m_p(int argc, VALUE *argv, VALUE re)
{
    long pos = rb_check_arity(argc, 1, 2) > 1 ? NUM2LONG(argv[1]) : 0;
    return rb_reg_match_p(re, argv[0], pos);
}

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

/R.../.match?("Ruby")    #=> true
/R.../.match?("Ruby", 1) #=> false
/P.../.match?("Ruby")    #=> false
$&                       #=> nil
named_captures → хеш Показать исходный код
static VALUE
rb_reg_named_captures(VALUE re)
{
    regex_t *reg = (rb_reg_check(re), RREGEXP_PTR(re));
    VALUE hash = rb_hash_new_with_size(onig_number_of_names(reg));
    onig_foreach_name(reg, reg_named_captures_iter, (void*)hash);
    return hash;
}

Возвращает хеш, представляющий информацию об именованных захватах rxp.

Ключ хеша — имя именованного захвата. Значение хеша — массив, который представляет список индексов соответствующих именованных захватов.

/(?<foo>.)(?<bar>.)/.named_captures
#=> {"foo"=>[1], "bar"=>[2]}

/(?<foo>.)(?<foo>.)/.named_captures
#=> {"foo"=>[1, 2]}

Если именованных захватов нет, возвращается пустой хеш.

/(.)(.)/.named_captures
#=> {}
names → [name1, name2, ...] Показать исходный код
static VALUE
rb_reg_names(VALUE re)
{
    VALUE ary;
    rb_reg_check(re);
    ary = rb_ary_new_capa(onig_number_of_names(RREGEXP_PTR(re)));
    onig_foreach_name(RREGEXP_PTR(re), reg_names_iter, (void*)ary);
    return ary;
}

Возвращает список имён захватов в виде массива строк.

/(?<foo>.)(?<bar>.)(?<baz>.)/.names
#=> ["foo", "bar", "baz"]

/(?<foo>.)(?<foo>.)/.names
#=> ["foo"]

/(.)(.)/.names
#=> []
options → целое число Показать исходный код
static VALUE
rb_reg_options_m(VALUE re)
{
    int options = rb_reg_options(re);
    return INT2NUM(options);
}

Возвращает набор битов, соответствующих параметрам, использованным при создании этого Regexp (см. Regexp::new для деталей. Обратите внимание, что дополнительные биты могут быть установлены в возвращаемых параметрах: они используются в коде регулярных выражений. Эти дополнительные биты игнорируются, если параметры передаются в Regexp::new).

Regexp::IGNORECASE                  #=> 1
Regexp::EXTENDED                    #=> 2
Regexp::MULTILINE                   #=> 4

/cat/.options                       #=> 0
/cat/ix.options                     #=> 3
Regexp.new('cat', true).options     #=> 1
/\xa1\xa2/e.options                 #=> 16

r = /cat/ix
Regexp.new(r.source, r.options)     #=> /cat/ix
source → str Показать исходный код
static VALUE
rb_reg_source(VALUE re)
{
    VALUE str;

    rb_reg_check(re);
    str = rb_str_dup(RREGEXP_SRC(re));
    if (OBJ_TAINTED(re)) OBJ_TAINT(str);
    return str;
}

Возвращает исходную строку шаблона.

/ab+c/ix.source #=> "ab+c"

Обратите внимание, что escape-последовательности сохраняются как есть.

/\x20\+/.source  #=> "\\x20\\+"
to_json(*) Показать исходный код
# File ext/json/lib/json/add/regexp.rb, line 27
def to_json(*)
  as_json.to_json
end

Сохраняет имя класса (Regexp) с параметрами o и исходным кодом s (Regexp или String) в виде строки JSON

to_s → str Показать исходный код
static VALUE
rb_reg_to_s(VALUE re)
{
    return rb_reg_str_with_term(re, '/');
}

Возвращает строку, содержащую регулярное выражение и его параметры (используя обозначение (?opts:source)). Эта строка может быть повторно использована для создания регулярного выражения с теми же семантическими свойствами, что и исходное. (Однако, Regexp#== может не возвращать true при сравнении двух выражений, так как сам источник регулярного выражения может отличаться, как показано в примере). Regexp#inspect генерирует более читабельную версию rxp.

r1 = /ab+c/ix           #=> /ab+c/ix
s1 = r1.to_s            #=> "(?ix-m:ab+c)"
r2 = Regexp.new(s1)     #=> /(?ix-m:ab+c)/
r1 == r2                #=> false
r1.source               #=> "ab+c"
r2.source               #=> "(?ix-m:ab+c)"
~ rxp → целое число или nil Показать исходный код
VALUE
rb_reg_match2(VALUE re)
{
    long start;
    VALUE line = rb_lastline_get();

    if (!RB_TYPE_P(line, T_STRING)) {
        rb_backref_set(Qnil);
        return Qnil;
    }

    start = rb_reg_search(re, line, 0, 0);
    if (start < 0) {
        return Qnil;
    }
    start = rb_str_sublen(line, start);
    return LONG2FIX(start);
}

Сопоставление — Сопоставляет rxp с содержимым $_. Эквивалентно rxp =~ $_.

$_ = "input data"
~ /at/   #=> 7

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API