/find me/.match 'Can you find me here?' # #<MatchData "find me">
.
, \w
, \d
, +
, *
, ?
и още +/-3?
Wait, forgot to escape a space. Wheeeeee[taptaptap]eeeeee.
Имаме следната задача:
Да се напише кратък Ruby expression, който проверява дали дадено число е просто или не, посредством употреба на регулярен израз. Резултатът от изпълнението му трябва да еtrue
за прости числа иfalse
за всички останали. Неща, които можете да ползвате:
- Самото число, разбира се.
- Произволни методи от класа
Regexp
- Подходящ регулярен израз (шаблон)
- Текстовия низ
'1'
.String#*
.- Някакъв условен оператор (например
if
-else
или? … : …
)true
,false
, ...
Имаме следната задача:
Да валидирате изрази от следния тип за правилно отворени/затворени скоби:
(car (car (car ...)))
- Например:
(car (car (car (car list))))
- Целта е израз, чийто резултат да може да се ползва в условен оператор (
true
/false
-еквивалент)- Можете да ползвате произволни методи от класа
Regexp
- И регулярен израз, разбира се
Сменете * на % ако тя не е екранирана (escape-ната)
foo*
=>foo%
foo\*
=>foo\*
foo\\\\*
=>foo\\\\%
*\**
=>%\*%
- Може и да стане без look-ahead/behind/... :)
Проверете дали нещо е валиден математически израз
- Произволно число цяло
1337
- Променлива (латинска малка буква)
x
- Операция между валидни изрази (+, -, *, /)
x + y - 21 / 3
- Скоби, ограждащи валидни изрази
-x * (y + -5 * (7 - 13)) / 44 - 9000
Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.
will liquify the nerves of the sentient whilst you observe, your psyche withering in the onslaught of horror
grep
, sed
, awk
, vi
, Emacs
...
Regexp
/pattern/
%r
, например: %r{/path/maching/made/easy}
Regexp
String
също има методи за работа с регулярни изразиRegexp#match
nil
, ако шаблонът не "хваща" нищо
MatchData
, ако шаблонът "хваща" нещо от низа
MatchData
в детайли — по-късно
/wool/
ще отговаря на точно тази последователност от символи в низ
(
, )
, [
, ]
, {
, }
, .
, ?
, +
, *
, ^
, $
, \
, ...
-
)/find me/.match 'Can you find me here?' # #<MatchData "find me">
/find me/.match 'You will not find ME!' # nil
.
съвпада с един произволен символ (с изключение на символите за нов ред)
[
и ]
се ползват за дефиниране на класове от символи
*
, ?
, +
, {
и }
се ползват за указване на повторения
^
, $
, \b
, \B
и т.н. са "котви" и съответстват на определени "междусимволни дупки" :)
|
има смисъл на "или", например:/day|nice/.match 'A nice dance-day.' # #<MatchData "nice">
/da(y|n)ce/.match 'A nice dance-day.' # #<MatchData "dance" 1:"n">
Внимавайте с приоритета на |
\
пред специален символ го прави неспециален такъв (екранира го)
\\
(като в обикновен низ)[
и ]
[a-z]
или [0-9A-F]
[a\-b]
[-abc]
или [abc-]
- тук то няма специален смисъл
^
, това означава "някой символ, който не е посочен в класа"
/W[aeiou]rd/.match "Word" # #<MatchData "Word">
/[0-9a-f]/.match '9f' # #<MatchData "9">
/[9f]/.match '9f' # #<MatchData "9">
/[^a-z]/.match '9f' # #<MatchData "9">
\w
- символ от дума ([a-zA-Z0-9_]
)
\W
- символ, който не може да участва в дума ([^a-zA-Z0-9_]
)
\d
- цифра ([0-9])
\D
- символ, който не е цифра ([^0-9]
)
\h
- шеснадесетична цифра ([0-9a-fA-F]
)
\H
- символ, който не е шеснадесетична цифра ([^0-9a-fA-F]
)
\s
- whitespace-символ (/[ \t\r\n\f]/
)
\S
- символ, който не е whitespace (/[^ \t\r\n\f]/
)[[:alpha:]]
- символ от азбука
[[:alnum:]]
- горното или цифра
[[:blank:]]
- интервал или таб
[[:cntrl:]]
- контролен символ
[[:digit:]]
- цифра
[[:lower:]]
- малка буква
[[:upper:]]
- главна буква
[[:print:]]
- printable-символ
[[:punct:]]
- пунктуационен символ
[[:space:]]
- whitespace-символ (вкл. и нов ред)
[[:xdigit:]]
- шеснадеситична цифра
[[:word:]]
- символ, който може да участва в дума (работи и за Unicode, за разлика от \w
)
[[:ascii:]]
- ASCII-символ\p{}
може да match-вате символи, имащи определено свойство (подобно на POSIX)
\p{Alnum}
, \p{Alpha}
, \p{Blank}
, \p{Cntrl}
, \p{Digit}
, \p{Graph}
\p{Katakana}
\p{Cyrillic}
, например:/\s\p{Cyrillic}\p{Cyrillic}\p{Cyrillic}/.match 'Ние сме на всеки километър!' # #<MatchData " сме">
^
съвпада с началото на ред (Ruby е в multiline режим по подразбиране)
$
съвпада с края на ред
\A
съвпада с началото на текстов низ
\z
съвпада с края на низ
\b
отговаря на граница на дума (когато е извън [
и ]
; вътре означава backspace
)
\B
отговаря на място, което не е граница на дума/real/.match "surrealist" # #<MatchData "real">
/\Areal/.match "surrealist" # nil
/\band/.match "Demand" # nil
/\Band.+/.match "Supply and demand curve" # #<MatchData "and curve">
s
s*
означава нула или повече повторения на s
s+
търси едно или повече повторения на s
s?
съвпада с нула или едно повторение на s
s{m,n}
означава между m и n повторения на s
m
или n
:
s{,n}
има смисъл на нула до n
повторения, а s{m,}
— поне m
повторения
s{n}
означава точно n
повторения/e+/.match 'Keeewl' # #<MatchData "eee">
/[Kke]+/.match 'Keeewl' # #<MatchData "Keee">
/\w+/.match '2038 - the year' # #<MatchData "2038">
/".*"/.match '"Quoted text!"' # #<MatchData "\"Quoted text!\"">
/[[:upper:]]+[[:lower:]]+l{2}o/.match 'Hello' # #<MatchData "Hello">
?
след повторителя
.*?
кара повторителя *
да се държи не-лакомо
/<.+>/.match("<a><b>") # #<MatchData "<a><b>">
/<.+?>/.match("<a><b>") # #<MatchData "<a>">
Символите (
и )
се използват за логическо групиране на части от шаблона с цел:
day
или dance
: /\bda(y|nce)\b/
Текстът, който match-ва частта на шаблона, оградена в скоби, може да се достъпва:
\1
за първата група, \2
за втората и т.н.
MatchData
-обекта
$1
, $2
... за номерирани групи
date_string = '2012-11-12'
date_parts = /\A(\d{4})-(\d\d)-(\d\d)\z/.match(date_string)
if date_parts
Date.new date_parts[1].to_i, date_parts[2].to_i, date_parts[3].to_i
# #<Date: 2012-11-12 ...>
end
(foo|bar)
, но не искаме тази група да се намесва в $1
, $2
, ...
(?:foo|bar)
/(\d+)(st|nd|rd|th)? (\w+)/.match '1st June' # #<MatchData "1st June" 1:"1" 2:"st" 3:"June">
/(\d+)(?:st|nd|rd|th)? (\w+)/.match '1st June' # #<MatchData "1st June" 1:"1" 2:"June">
/(\d+)(st|nd|rd|th)? (\w+)/.match '1 June' # #<MatchData "1 June" 1:"1" 2:nil 3:"June">
/(\d+)(?:st|nd|rd|th)? (\w+)/.match '1 June' # #<MatchData "1 June" 1:"1" 2:"June">
=~
и !~
— дефинирани в Regexp
и в String
/pattern/ =~ 'Some string'
'Some string' =~ /pattern/
nil
, ако няма съвпадение, или число (offset), ако има такова
$1
, $~
...)
if
log_entry = "[2011-07-22 15:42:12] - GET / HTTP/1.1 200 OK"
if log_entry =~ /\bHTTP\/1\.1 (\d+)/
request_status = $1.to_i # 200
else
raise "Malformed log entry!"
end
date_string = '2012-11-12'
if date_string =~ /\A(\d{4})-(\d\d)-(\d\d)\z/
Date.new $1.to_i, $2.to_i, $3.to_i # #<Date: 2012-11-12 ...>
end
(?<name>)
или така: (?'name')
, където name
е името на групата
(?<date>\d{4}-\d{2}-\d{2})
/(?<date>\d{4}-\d{2}-\d{2})/.match 'Today is 2011-11-08, Tuesday.' # #<MatchData "2011-11-08" date:"2011-11-08">
\1
, \2
и прочее, ако групите ви не са именовани
\11
се обръща към 11-тата група
\1
, последван от символа 1
"?
\k<group_identifier>
, където group_identifier
е число или име на група
/(?<word>\w+), \k<word>/
/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/.match 'Today is 2011-11-08, Tuesday.'
# #<MatchData "2011-11-08" year:"2011" month:"11" day:"08">
/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\11/.match 'Regular expressions'
# #<MatchData "ular express" 1:"u" 2:"l" 3:"a" 4:"r" 5:" " 6:"e" 7:"x" 8:"p" 9:"r" 10:"e" 11:"s">
/(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)\k<11>1/.match 'Regular express1ions'
# #<MatchData "ular express1" 1:"u" 2:"l" 3:"a" 4:"r" 5:" " 6:"e" 7:"x" 8:"p" 9:"r" 10:"e" 11:"s">
/(\w+), \1/.match 'testing, testing' # #<MatchData "testing, testing" 1:"testing">
/(\w+), \1/.match 'testing, twice' # nil
/(?<word>\w+), \k<word>/.match 'testing, testing' # #<MatchData "testing, testing" word:"testing">
/".*"/.match '"Quoted"' # #<MatchData "\"Quoted\"">
Частта от шаблона .*
хваща Quoted"
, тъй като е алчна. Това води до невъзможност да се намери съвпадение и алгоритъмът backtrack-ва -- връща се една стъпка/символ назад.
(?>pattern)
/"(?>.*)"/.match('"Quote"') # nil
\g<name>
, където name
е номер или име на група в шаблона
/(\w+), \1/.match 'testing, twice' # nil
/(\w+), \g<1>/.match 'testing, twice' # #<MatchData "testing, twice" 1:"twice">
Да валидирате изрази от следния тип за правилно отворени/затворени скоби:
(car (car (car ...)))
- Например:
(car (car (car (car list))))
- Целта е израз, чийто резултат да може да се ползва в условен оператор (
true
/false
-еквивалент)- Можете да ползвате произволни методи от класа
Regexp
- И регулярен израз, разбира се
validator = /^(\(car (\g<1>*|\w*)\))$/
valid = '(car (car (car (car list))))'
invalid = '(car (car (car list))'
validator.match(valid) ? true : false # true
validator.match(invalid) ? true : false # false