Имаме следната задача:
Да се напише кратък Ruby expression, който проверява дали дадено число е просто или не, посредством употреба на регулярен израз. Резултатът от изпълнението му трябва да еtrue
за прости числа иfalse
за всички останали. Неща, които можете да ползвате:
- Самото число, разбира се.
- Произволни методи от класа
Regexp
- Подходящ регулярен израз (шаблон)
- Текстовия низ
'1'
.String#*
.- Някакъв условен оператор (например
if
-else
или? … : …
)true
,false
, ...
Имаме следната задача:
Да валидирате изрази от следния тип за правилно отворени/затворени скоби:
(car (car (car ...)))
- Например:
(car (car (car (car list))))
- Целта е израз, чийто резултат да може да се ползва в условен оператор (
true
/false
-еквивалент)- Можете да ползвате произволни методи от класа
Regexp
- И регулярен израз, разбира се
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
=~
и !~
— дефинирани в 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">
\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
'1' * числото =~ /някакъв регулярен израз/ ? false : true
'1' * 13 =~ /^1?$|^(11+?)\1+$/ ? false : true
/(?=pattern)/
/(?!pattern)/
/(?<=pattern)/
/(?<!pattern)/
/(?<=<b>)\w+(?=<\/b>)/.match("Fortune favours the <b>bold</b>") # #<MatchData "bold">
Regexp#match
$~
Regexp.last_match
Enumerable
MatchData#[група]
, където група
е номер или име на група, ви връща порцията текст, отговаряща на съответната група
MatchData#begin(група)
пък ви връща число — отместването спрямо началото на низа на порцията текст, отговаряща на съответната група
/(\w+)/.match('Some words')[1] # "Some"
/(\w+)/.match('Some words').begin(1) # 0
/(?<id>\d+)/.match('ID: 12345')[:id] # "12345"
/(?<id>\d+)/.match('ID: 12345').begin(:id) # 4
MatchData#pre_match
(същото като специалната променлива $`
) — текстът преди съвпадението
MatchData#post_match
(същото като специалната променлива $'
) — текстът след съвпадението
match = /(?<number>\d+)/.match 'ID: 12345 (new)'
match[:number] # "12345"
match.pre_match # "ID: "
match.post_match # " (new)"
$~
, $'
, $1
, $2
, $3
и прочее
match
Regexp#match
html = '<h1>Header</h1>' # или:
html = '<img src="http://my/image.src" alt="Kartman Makes Burgers" />'
case html
when /(<h(\d)>)(.+)<\/h\2>/
{header: $3, size: $2}
when /<a\s+href="([^"]+)">([^<]+)<\/a>/
{url: $1, text: $2}
when /<img\s+src="([^"]+)"\s+alt="([^"]+)"\s*\/>/
{image: $1, alt: $2}
else
'unrecognized tag'
end
# {:image=>"http://my/image.src", :alt=>"Kartman Makes Burgers"}
String#match
String#=~
и String#!=
String#sub
, String#gsub
и вариантите им с !
String#[]
и String#slice
- в някои от вариантите си приемат регулярен израз
String#index
и rindex
приемат и регулярен израз
String#partition
и rpartition
и други...'SomeTitleCase'.gsub /(^|[[:lower:]])([[:upper:]])/ do
[$1, $2.downcase].reject(&:empty?).join('_')
end
# "some_title_case"
Regexp#encoding
/something/u
за UTF-8
Rubyのお父さんはまつもとゆきひろさんです。
unicode_test = 'Rubyのお父さんはまつもとゆきひろさんです。'
/は[[:alpha:]]+さん/.match unicode_test # #<MatchData "はまつもとゆきひろさん">
\b
в Unicode-текст работи, когато границата на думата е лесно определима
/\b[[:alpha:]]\b/.match 'това и онова' # #<MatchData "и">
Rubyのお父さんはまつもとゆきひろさんです。
?Например:
'Ruby no otousan ha Matsumoto Yukihiro san desu.'.gsub(/(\b[[:alpha:]]+\b)/) { "[#{$1}]" }
# "[Ruby] [no] [otousan] [ha] [Matsumoto] [Yukihiro] [san] [desu]."
Но:
'Rubyのお父さんはまつもとゆきひろさんです。'.gsub(/(\b[[:alpha:]]+\b)/) { "[#{$1}]" }
# "[Rubyのお父さんはまつもとゆきひろさんです]。"
/pattern/flags
i
прави търсенето на съвпадение нечувствително към регистъра на буквите
u
кара шаблона да носи задължителна кодировка UTF-8
m
превръща шаблона в multiline-такъв (в този режим, например, .
ще съвпада и с нов ред)
Regexp
: http://www.ruby-doc.org/core-1.9.3/Regexp.html
MatchData
: http://www.ruby-doc.org/core-1.9.3/MatchData.html
ri
, например: ri Regexp#=~
RE: <моят въпрос>
, той ще го Google-не вместо вас и ще ви върне отговор в body-то на email-а