faiwer
@faiwer
frontend-developer

Каким должно быть регулярное выражение для замены относительных ссылок на абсолютные (RSS)?

Доброго времени суток. Я очень люблю регулярные выражения, но довольно часто в них плаваю, когда решаю не самую тривиальную задачу. Вот и сейчас… У меня есть rss, и моя задача заменить в нём все относительные пути на абсолютные. Я пришёл к следующему решению:

static public function relative_to_absolute( $text )
	{
		$rg =
			'#'.
				'(<\w+\s.*)'. // "<img "
				'(href|src)\s*=\s*'. // "src = "
				'(?:'.
					'\'([^\']+)\''.'|'. // 'relative'
					'\"([^\"]+)\"'. // "relative"
				')'.
			'#';

		$replace = $text;
		$index = Kohana::$base_url !== '/';

		do
		{
			$text = $replace;

			$replace = preg_replace_callback( $rg, function( $m ) use ( $index )
			{
				$url = empty( $m[ 3 ] ) ? $m[ 4 ] : $m[ 3 ];

				if( strpos( $url, '//' ) === false )
				{
					return $m[ 1 ].$m[ 2 ].'="'.URL::site( $url, 'http', $index ).'"';
				}
				else
				{
					return $m[ 0 ];
				}
			}, $replace );
		}
		while( $text !== $replace );

		return $replace;
	}



Оно работает, но мне не нравится по следующим причинам:


1. Железно вбитые аттрибуты. Оно как бы и не критично, но хочется более универсальное решение. Проблема в том — как отличить относительный url от просто значения аттрибута.

2. Дубляж того участка кода, который отвечает за саму ссылку в кавычках, в виду того, что они могут быть как ' так и ". Если написать что-то вроде '|" то как быть со ссылками содержащими кавычку (например транслит от «ь»).

3. Регулярка пропускает все url, и уже внутри определяет какие относительные, а какие нет. Как можно отфильтровать абсолютные ещё на стадии preg_replace-а? Я догадываюсь что там нужна ретроспективная отрицательная проверка, но вот как её туда воткнуть не понимаю.


В общем, мне кажется, что сию задачу можно решить без _callback-а. Интересует не готовое решение, а понимание его принципа работы :)
  • Вопрос задан
  • 4737 просмотров
Решения вопроса 1
faiwer
@faiwer Автор вопроса
frontend-developer
В JavaScript много чего нет в поддержке регулярок. Только самый минимум. Про ретроспективную негативную проверку я знаю, сам же выше и написал про неё :) До сих пор не придумал как её здесь можно развернуть. Зато придумал решение с опережающей позитивной проверкой. Получилось так:

	static public function relative_to_absolute( $text )
	{
		$rg =
			'#'.
				'(<\w+\s.*)'. // "<img "
				'(href|src)\s*=\s*'. // "src = "
				'(?:'.
					'\'(?![\w:]+//)/?([^\']+)\''.'|'. // 'relative'
					'\"(?![\w:]+//)/?([^\"]+)\"'. // "relative"
				')'.
			'#';

		$replace = $text;
		$host = self::base('http');

		do
		{
			$text = $replace;
			$replace = preg_replace( $rg, '$1$2="'.$host.'$4"', $replace );
		}
		while( $text !== $replace );

		return $replace;
	}

(?![\w:]+//) — «говорит» о том, что после кавычки не будет протокола,
/? — игнорирует лидирующий слеш на случай если таковой имеется, ибо в $host он уже есть.

Осталась только проблема с дублированием кода для одинарных и двойных кавычек. Но тут, честно говоря, мне кажется решений в лоб и не существует :)
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
taliban
@taliban
php программист
index = "http://index.com"; "<img src='/relative'>".replace(/src='(\/.*?)'/, "src='"+index+"$1")

Думаю не составить труда перевести код с JavaScript =)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы