0

I need a regex that will determine if a string is a tweet URL. I've got this

Regexp.new(/http:|https:\/\/(twitter\.com\/.*\/status\/.*|twitter\.com\/.*\/statuses\/.*|www\.twitter\.com\/.*\/status\/.*|www\.twitter\.com\/.*\/statuses\/.*|mobile\.twitter\.com\/.*\/status\/.*|mobile\.twitter\.com\/.*\/statuses\/.*)/i)

Why does it return true for the following?

"https://i.sstatic.net/QdOS0.jpg".match(Regexp.new(/http:|https:\/\/(twitter\.com\/.*\/status\/.*|twitter\.com\/.*\/statuses\/.*|www\.twitter\.com\/.*\/status\/.*|www\.twitter\.com\/.*\/statuses\/.*|mobile\.twitter\.com\/.*\/status\/.*|mobile\.twitter\.com\/.*\/statuses\/.*)/i))? true : false
    => true
5
  • If you use Regexp.new('http://', 'i'), you safe yourself some escaping troubles. Commented Feb 8, 2011 at 9:49
  • 1
    see strfriend Commented Feb 8, 2011 at 9:52
  • Answer is already given but I just want to leave this site here, it always helps me out greatly when struggling with regexps: Rubular Commented Feb 8, 2011 at 9:58
  • @Maran, notice: this site uses 1.8.7. Commented Feb 8, 2011 at 9:59
  • @giraff Or use %r{http://...} Commented Feb 8, 2011 at 14:39

6 Answers 6

4

http: will always match a URL starting with http:

Try the following:

/https?:\/\/(twitter\.com\/.*\/status\/.*|twitter\.com\/.*\/statuses\/.*|www\.twitter\.com\/.*\/status\/.*|www\.twitter\.com\/.*\/statuses\/.*|mobile\.twitter\.com\/.*\/status\/.*|mobile\.twitter\.com\/.*\/statuses\/.*)/i

The question mark will make the s optional, thus matching http or https.

Sign up to request clarification or add additional context in comments.

Comments

2

Your regex could be abbreviated like :

#^https?://(:?www\.|mobile\.)?twitter\.com/.*?/status(:?es)?/.*#i

explanation:

#                       regex delimiter
^                       start of line
https?                  http or https
://                     ://
(:?                     start of non capture group
www\.|mobile\.          www. or mobile.
)?                      end of group
twitter\.com/           twitter.com
.*?                     any number of any char not greedy
/status                 /status
(:?es)?                 non capture group that contains possibly  `es`
/.*                     / followed by any number of any char
$                       end of string
#i                      delimiter and case insensitive

Comments

2

No need for regular expressions here (as usual).

require 'uri'
uri = URI.parse("http://www.twitter.com/status/12345")
p uri.host.split('.')[-2] == 'twitter' # returns true

More docs at: http://ruby-doc.org/stdlib/

1 Comment

+1 for cutting to the chase and sidestepping the regex bullet.
1

You should group your OR-Clauses, like this:

(http:|https:)

Additionally, it wouldn't hurt to specify beginning and end of it:

^(http:|https:).*$

1 Comment

Or, if you don't need to capture the clause, (?:http:|https:).
0

The start of your regex specifies an option of just 'http:', which naturally matches the URL you are testing. Depending on how strict you need your check to be, you could just remove the http/https parts from the start of the regex.

Comments

0

While many other answers show you a better regex, the answer is because /foo|bar/ will match either foo or bar, and what you wrote was /http:|.../, hence all URLs will be matched.

See @giraff's answer for how you could have written the alternation to do what you expect, or @M42's or @Koraktor's answers for a better regexp.

And as posted in the comments, note that you can write a regex literal as %r{...} instead of /.../, which is nice when you want to use / characters in your regex without escaping them.

1 Comment

I like the %r-Syntax, but how would you add the i-modifier to it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.