3 * @author Mike Cochrane <mikec@mikenz.geek.nz>
4 * @author Nick Pope <nick@nickpope.me.uk>
5 * @copyright Copyright © 2010, Mike Cochrane, Nick Pope
6 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
11 * Twitter Regex Abstract Class
13 * Used by subclasses that need to parse tweets.
15 * Originally written by {@link http://github.com/mikenz Mike Cochrane}, this
16 * is based on code by {@link http://github.com/mzsanford Matt Sanford} and
17 * heavily modified by {@link http://github.com/ngnpope Nick Pope}.
19 * @author Mike Cochrane <mikec@mikenz.geek.nz>
20 * @author Nick Pope <nick@nickpope.me.uk>
21 * @copyright Copyright © 2010, Mike Cochrane, Nick Pope
22 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License v2.0
25 abstract class Twitter_Regex {
28 * Expression to at sign characters
32 const REGEX_AT_SIGNS = '[@@]';
35 * Expression to match characters that may come before a URL.
39 const REGEX_URL_CHARS_BEFORE = '(?:[^-\\/"\':!=a-z0-9_@@]|^|\\:)';
42 * Expression to match the domain portion of a URL.
46 const REGEX_URL_DOMAIN = '(?:[^\\p{P}\\p{Lo}\\s][\\.-](?=[^\\p{P}\\p{Lo}\\s])|[^\\p{P}\\p{Lo}\\s])+\\.[a-z]{2,}(?::[0-9]+)?';
49 * Expression to match handful of probable TLDs for protocol-less URLS.
53 const REGEX_PROBABLE_TLD = '/\\.(?:com|net|org|gov|edu)$/iu';
56 * Expression to match characters that may come in the URL path.
60 const REGEX_URL_CHARS_PATH = '(?:(?:\\([a-z0-9!\\*\';:=\\+\\$\\/%#\\[\\]\\-_,~]+\\))|@[a-z0-9!\\*\';:=\\+\\$\\/%#\\[\\]\\-_,~]+\\/|[\\.\\,]?(?:[a-z0-9!\\*\';:=\\+\\$\\/%#\\[\\]\\-_~]|,(?!\s)))';
63 * Expression to match characters that may come at the end of the URL path.
67 const REGEX_URL_CHARS_PATH_END = '[a-z0-9=#\\/]';
70 * Expression to match characters that may come in the URL query string.
74 const REGEX_URL_CHARS_QUERY = '[a-z0-9!\\*\'\\(\\);:&=\\+\\$\\/%#\\[\\]\\-_\\.,~]';
77 * Expression to match characters that may come at the end of the URL query
82 const REGEX_URL_CHARS_QUERY_END = '[a-z0-9_&=#\\/]';
85 * Expression to match a username followed by a list.
89 const REGEX_USERNAME_LIST = '/([^a-z0-9_\/]|^|RT:?)([@@]+)([a-z0-9_]{1,20})(\/[a-z][-_a-z0-9\x80-\xFF]{0,24})?([@@\xC0-\xD6\xD8-\xF6\xF8-\xFF]?)/iu';
92 * Expression to match a username mentioned anywhere in a tweet.
96 const REGEX_USERNAME_MENTION = '/(^|[^a-z0-9_])[@@]([a-z0-9_]{1,20})([@@\xC0-\xD6\xD8-\xF6\xF8-\xFF]?)/iu';
99 * Expression to match a hashtag.
103 const REGEX_HASHTAG = '/(^|[^0-9A-Z&\/\?]+)([##]+)([0-9A-Z_]*[A-Z_]+[a-z0-9_üÀ-ÖØ-öø-ÿ]*)/iu';
106 * Expression to match whitespace.
108 * Single byte whitespace characters
109 * 0x0009-0x000D White_Space # Cc # <control-0009>..<control-000D>
110 * 0x0020 White_Space # Zs # SPACE
111 * 0x0085 White_Space # Cc # <control-0085>
112 * 0x00A0 White_Space # Zs # NO-BREAK SPACE
113 * Multi byte whitespace characters
114 * 0x1680 White_Space # Zs # OGHAM SPACE MARK
115 * 0x180E White_Space # Zs # MONGOLIAN VOWEL SEPARATOR
116 * 0x2000-0x200A White_Space # Zs # EN QUAD..HAIR SPACE
117 * 0x2028 White_Space # Zl # LINE SEPARATOR
118 * 0x2029 White_Space # Zp # PARAGRAPH SEPARATOR
119 * 0x202F White_Space # Zs # NARROW NO-BREAK SPACE
120 * 0x205F White_Space # Zs # MEDIUM MATHEMATICAL SPACE
121 * 0x3000 White_Space # Zs # IDEOGRAPHIC SPACE
125 const REGEX_WHITESPACE = '[\x09-\x0D\x20\x85\xA0]|\xe1\x9a\x80|\xe1\xa0\x8e|\xe2\x80[\x80-\x8a,\xa8,\xa9,\xaf\xdf]|\xe3\x80\x80';
128 * Contains the complete valid URL pattern string.
130 * This should be generated the first time the constructor is called.
132 * @var string The regex pattern for a valid URL.
134 protected static $REGEX_VALID_URL = null;
137 * Contains the reply username pattern string.
139 * This should be generated the first time the constructor is called.
141 * @var string The regex pattern for a reply username.
143 protected static $REGEX_REPLY_USERNAME = null;
146 * The tweet to be used in parsing. This should be populated by the
147 * constructor of all subclasses.
151 protected $tweet = '';
154 * This constructor is used to populate some variables.
156 * @param string $tweet The tweet to parse.
158 protected function __construct($tweet) {
159 if (is_null(self::$REGEX_VALID_URL)) {
160 self::$REGEX_VALID_URL = '/(?:' # $1 Complete match (preg_match already matches everything.)
161 . '('.self::REGEX_URL_CHARS_BEFORE.')' # $2 Preceding character
162 . '(' # $3 Complete URL
163 . '((?:https?:\\/\\/|www\\.)?)' # $4 Protocol (or www)
164 . '('.self::REGEX_URL_DOMAIN.')' # $5 Domain(s) (and port)
165 . '(\\/'.self::REGEX_URL_CHARS_PATH.'*' # $6 URL Path
166 . self::REGEX_URL_CHARS_PATH_END.'?)?'
167 . '(\\?'.self::REGEX_URL_CHARS_QUERY.'*' # $7 Query String
168 . self::REGEX_URL_CHARS_QUERY_END.')?'
172 if (is_null(self::$REGEX_REPLY_USERNAME)) {
173 self::$REGEX_REPLY_USERNAME = '/^('.self::REGEX_WHITESPACE.')*[@@]([a-zA-Z0-9_]{1,20})/';
175 $this->tweet = $tweet;