I have a NSString that will store data coming from a UITextField, these data should follow a certain pattern that would be:
[0-9] / [0-9] / [0-9]
In this case the content that User type must follow this pattern. I try to do something like this, but doesn't work:
if([myString isEqual: #"[0-9]/[0-9]/[0-9]"]){
/* ...Others code here! */
}
I believe in Objective-C Have a specific way to treat a regex, how can I be doing this?
Thanks.
Assuming you want to allow optional spaces around the slashes as in your [0-9] / [0-9] / [0-9] example, this regex matches your pattern:
^(?:\[\d-\d\]\s*(?:/\s*|$)){3}$
Note that in your regex string, you may have to escape each backslash with a backslash.
Explain Regex
^ # the beginning of the string
(?: # group, but do not capture (3 times):
\[ # '['
\d # digits (0-9)
- # '-'
\d # digits (0-9)
\] # ']'
\s* # whitespace (\n, \r, \t, \f, and " ") (0
# or more times (matching the most amount
# possible))
(?: # group, but do not capture:
/ # '/'
\s* # whitespace (\n, \r, \t, \f, and " ")
# (0 or more times (matching the most
# amount possible))
| # OR
$ # before an optional \n, and the end of
# the string
) # end of grouping
){3} # end of grouping
$ # before an optional \n, and the end of the
# string
Related
I have a piece of code, where I can switch words from #post.swap_content to hyperlinks by keyword. For example, I have a word 'michigan' in #post.swap_content and I have keyword 'Michigan' in keywords, so it would switch it to the hyperlink that attached to keyword. Here is part of the function:
def execute
all_keys = Keyword.all.pluck(:key, :link).to_h.transform_keys(&:downcase)
#post.swap_content = #post.swap_content.to_s.gsub!(/\w+/) do |word|
url = all_keys[word.downcase]
url ? "<a href='#{url}'>#{word}</a>" : word
end
#post.save!
end
And my question is - how can I make it gsub only the first two keywords in #post.swap_content? For example, I have #post.swap_content 'michigan, michigan and michigan, utah and utah', how can I switch to hyperlinks only first two keywords(first two 'michigan' and first two 'utah')? I think, that I need somehow to work gsub but I don't know hot to manage number of words that can be gsub.
You can provide a block to gsub that will be invoked with each match, you could use this to count occurences and condtionally replace content.
str = "Dog dog dog cat cat cat"
occurences = {}
str.gsub(/\w+/) do |match|
# downcase so Dog and dog are counted together
key = match.downcase
# build a hash which counts the number of times we've matched a word.
count = occurences.store(key, occurences.fetch(key, 0).next)
# return the word unchanged or wrap in a hyperlink depending on count
count > 2 ? match : "<a>#{match}</a>"
end
# output => "<a>Dog</a> <a>dog</a> dog <a>cat</a> <a>cat</a> cat"
Suppose:
str = "Dog dog cat dog cat Dog cat cat"
If Ruby's regex engine supported variable-length negative lookbehinds we could write:
R = /\b(\w+)\b(?<!(?:\b\1\b.*){2})/i
str.gsub(R, '<a>\1</a>')
#=> "<a>Dog</a> <a>dog</a> <a>cat</a> dog <a>cat</a> Dog cat cat"
We can write this regular expression in free-spacing mode to make it self-documenting:
R = /
\b # assert a word break
(\w+) # match 1+ word characters and save to capture group 1
\b # assert a word break
(?! # begin a negative lookbehind
(?: # begin a non-capture group
\b # assert a word break
\1 # match the content of capture group 1
\b # assert a word break
.* # match 0+ characters
) # end non-capture group
{2} # execute non-capture group twice
) # end negative lookbehind
/ix # assert case-independent and free-spacing regex def modes
Unfortunately, Ruby's regex engine does not support variable-length (positive or negative) lookbehinds (though one day it might). It does, however, support variable-length (positive and negative) lookaheads. We therefore could reverse the string, perform the desired replacements using gsub then reverse the resulting string, as follows:
R = /\b(\w+)\b(?!(?:.*\b\1\b){2})/i
str.reverse.gsub(R, '>a/<\1>a<').reverse
#=> "<a>Dog</a> <a>dog</a> <a>cat</a> dog <a>cat</a> Dog cat cat"
The steps are as follows.
s = str.reverse
#=> "tac tac goD tac god tac god goD"
t = s.gsub(R, '>a/<\1>a<')
#=> "tac tac goD >a/<tac>a< god >a/<tac>a< >a/<god>a< >a/<goD>a<"
t.reverse
#=> "<a>Dog</a> <a>dog</a> <a>cat</a> dog <a>cat</a> Dog cat cat"
Let's have a closer look at the regular expression.
R = /
\b # assert a word break
(\w+) # match 1+ word characters and save to capture group 1
\b # assert a word break
(?! # begin a negative lookahead
(?: # begin a non-capture group
.* # match 0+ characters
\b # assert a word break
\1 # match the content of capture group 1
\b # assert a word break
) # end non-capture group
{2} # execute non-capture group twice
) # end negative lookahead
/ix # assert case-independent and free-spacing regex def modes
I would like to extract video ids from potentially different URLs
https://www.facebook.com/{page-name}/videos/{video-id}/
https://www.facebook.com/{username}/videos/{video-id}/
https://www.facebook.com/video.php?id={video-id}
https://www.facebook.com/video.php?v={video-id}
How can I retrieve the video ids with a single ruby regex?
I haven't managed to convert this to Ruby regex but I (partially) managed to write it in standard JS regex:
^(https?://www\.facebook\.com/(?:video\.php\?v=\d+|.*?/videos/\d+))$
When I run the following code in Ruby it gives me an error:
text = "https://www.facebook.com/pili.morillo.56/videos/352355988613922/"
id = text.gsub( ^(https?://www\.facebook\.com/(?:video\.php\?v=\d+|.*?/videos/\d+))$ )
Here is the regexp I came up with: /(?<=\/videos\/)\d+?(?=\/|$)|(?<=[?&]id=)\d+?(?=&|$)|(?<=[?&]v=)\d+?(?=&|$)/
Breaking this up we can get this:
(?<=\/videos\/)\d+(?=\/|$)|
(?<=[?&]id=)\d+(?=&|$)|
(?<=[?&]v=)\d+(?=&|$)
Each of the three options follow the following simple structure: (?<=beforeMatch)target(?=afterMatch).
Here is the first as an example:
(?<=\/videos\/) # Positive lookbehind
\d+ # Matching the digits
(?=\/|$) # Positive lookahead
So, this means, match \d+ any digit, as long as it's preceeded by \/videos\/ and followed by \/ or it's the end of the line.
Therefore, we can match by 'id=', 'v=' or 'videos/'.
The full explaination:
(?<=\/videos\/) # Match as long as preceeded by '\/videos\/'
\d+ # Matching the id digits
(?=\/|$) # As long as it's followed by '\/' or the EOL
| # Or
(?<=[?&]id=) # Match as long as preceeded by '?id' or '&id'
\d+ # Matching the id digits
(?=&|$) # As long as it's followed by either '&' or the EOL
| # Or
(?<=[?&]v=) # Match as long as preceeded by '?v' or '&v'
\d+ # Matching the id digits
(?=&|$) # As long as it's followed by either '&' or the EOL
Where 'EOL' means end of line.
RE = %r[https://www.facebook.com/(?:.+?/)?video(?:.*?[/=])(.+?)(?:/?\z)]
%w[
https://www.facebook.com/{page-name}/videos/{video-id}/
https://www.facebook.com/{username}/videos/{video-id}/
https://www.facebook.com/video.php?id={video-id}
https://www.facebook.com/video.php?v={video-id}
].map { |url| url[RE, 1] }
#⇒ ["{video-id}", "{video-id}", "{video-id}", "{video-id}"]
You might use:
^https?:\/\/www\.facebook\.com\/.*?video(?:s|\.php.*?[?&](?:id|v)=)\/?([^\/&\n]+).*$
That would match
Begin of the string and begin url
^https?:\/\/www\.facebook\.com\/
Followed by:
.*? # Match any character zero or more times
video # Match video
(?: # Non capturing group
s # Match s
| # Or
\.php # Match .php
.*? # Match any character zero or more times
[?&] # Match ? or &
(?:id|v)= # Match id or v in non capturing group followed by =
) # Close non capturing group
\/? # Match optional /
( # Capturing group (group 1)
[^\/&\n]+ # Match not / or & or newline
) # Close capturing group
.* # Match any character zero or more times
$ # End of the string
text = "https://www.facebook.com/pili.morillo.56/videos/352355988613922/"
id = text.gsub(/^https?:\/\/www\.facebook\.com\/.*?video(?:s|\.php.*?[?&](?:id|v)=)\/?([^\/&\n]+).*$/, "\\1")
puts id
That will result in: 352355988613922
Demo
Say I have a string like this
"some3random5string8"
I want to insert spaces after each integer so it looks like this
"some3 random5 string8"
I specifically want to do this using gsub but I can't figure out how to access the characters that match my regexp.
For example:
temp = "some3random5string8"
temp.gsub(/\d/, ' ') # instead of replacing with a ' ' I want to replace with
# matching number and space
I was hoping there was a way to reference the regexp match. Something like $1 so I could do something like temp.gsub(/\d/, "#{$1 }") (note, this does not work)
Is this possible?
From the gsub docs:
If replacement is a String it will be substituted for the matched
text. It may contain back-references to the pattern’s capture groups
of the form \d, where d is a group number, or \k, where n is a
group name. If it is a double-quoted string, both back-references must
be preceded by an additional backslash.
This means the following 3 versions will work
>> "some3random5string8".gsub(/(\d)/, '\1 ')
=> "some3 random5 string8 "
>> "some3random5string8".gsub(/(\d)/, "\\1 ")
=> "some3 random5 string8 "
>> "some3random5string8".gsub(/(?<digit>\d)/, '\k<digit> ')
=> "some3 random5 string8 "
Edit: also if you don't want to add an extra space at the end, use a negative lookahead for the end of line, e.g.:
>> "some3random5string8".gsub(/(\d(?!$))/, '\1 ')
=> "some3 random5 string8"
A positive lookahead checking for a "word character" would also work of course:
>> "some3random5string8".gsub(/(\d(?=\w))/, '\1 ')
=> "some3 random5 string8"
Last but not least, the simplest version without a space at the end:
>> "some3random5string8".gsub(/(\d)(\w)/, '\1 \2')
=> "some3 random5 string8"
gsubtakes a block, which for me is easier to remember than the block-less way of getting the match.
"some3random5string8".gsub(/\d/){|digit| digit << " "}
Not sure about ruby syntax, but:
temp.gsub(/(\d)/, '$1 ')
or
temp.gsub(/(\d)/, '\1 ')
To be sure you insert space between number and a non number(i.e. letter or special char):
temp.gsub(/(\d)(\D)/, '$1 $2')
I am not very familiar with ruby, but I expect you can capture the digit, and then insert into replacement like this...
temp.gsub(/(\d)/, '$1 ')
unless (place =~ /^\./) == 0
I know the unless is like if not but what about the condtional?
=~ means matches regex
/^\./ is a regular expression:
/.../ are the delimiters for the regex
^ matches the start of the string or of a line (\A matches the start of the string only)
\. matches a literal .
It checks if the string place starts with a period ..
Consider this:
p ('.foo' =~ /^\./) == 0 # => true
p ('foo' =~ /^\./) == 0 # => false
In this case, it wouldn't be necessary to use == 0. place =~ /^\./ would suffice as a condition:
p '.foo' =~ /^\./ # => 0 # 0 evaluates to true in Ruby conditions
p 'foo' =~ /^\./ # => nil
EDIT: /^\./ is a regular expression. The start and end slashes denotes that it is a regular expression, leaving the important bit to ^\.. The first character, ^ marks "start of string/line" and \. is the literal character ., as the dot character is normally considered a special character in regular expressions.
To read more about regular expressions, see Wikipedia or the excellent regular-expressions.info website.
Hey... how would you validate a full_name field (name surname).
Consider names like:
Ms. Jan Levinson-Gould
Dr. Martin Luther King, Jr.
Brett d'Arras-d'Haudracey
Brüno
Instead of validating the characters that are there, you might just want to ensure some set of characters is not present.
For example:
class User < ActiveRecord::Base
validates_format_of :full_name, :with => /\A[^0-9`!##\$%\^&*+_=]+\z/
# add any other characters you'd like to disallow inside the [ brackets ]
# metacharacters [, \, ^, $, ., |, ?, *, +, (, and ) need to be escaped with a \
end
Tests
Ms. Jan Levinson-Gould # pass
Dr. Martin Luther King, Jr. # pass
Brett d'Arras-d'Haudracey # pass
Brüno # pass
John Doe # pass
Mary-Jo Jane Sally Smith # pass
Fatty Mc.Error$ # fail
FA!L # fail
#arold Newm#n # fail
N4m3 w1th Numb3r5 # fail
Regular expression explanation
NODE EXPLANATION
--------------------------------------------------------------------------------
\A the beginning of the string
--------------------------------------------------------------------------------
[^`!##\$%\^&*+_=\d]+ any character except: '`', '!', '#', '#',
'\$', '%', '\^', '&', '*', '+', '_', '=',
digits (0-9) (1 or more times (matching
the most amount possible))
--------------------------------------------------------------------------------
\z the end of the string
Any validation you perform here is likely to break down unless it is extremely general. For instance, enforcing a minimum length of 3 is probably about as reasonable as you can get without getting into the specifics of what is entered.
When you have names like "O'Malley" with an apostrophe, "Smith-Johnson" with a dash, "Andrés" with accented characters or extremely short names such as "Vo Ly" with virtually no characters at all, how do you validate without excluding legitimate cases? It's not easy.
At least one space and at least 4 char (including the space)
\A(?=.* )[^0-9`!##\\\$%\^&*\;+_=]{4,}\z