Есть ли способ использовать preg_replace()
для добавления строки « utm=some&medium=stuff
» в конце всех найденных URL-адресов, найденных в $html_text?
$html_text = 'Lorem ipsum <a href="http://www.me.com">dolor sit</a> amet, <a href="http://www.me.com/page.php?id=10">consectetur</a> elit.';
Таким образом, результат должен быть
href="http://www.me.com" ››››› href="http://www.me.com?utm=some&medium=stuff" href="http://www.me.com/page.php?id=1" ››››› href="http://www.me.com/page.php?id=1&utm=some&medium=stuff"
Итак, если URL-адрес содержит знак вопроса (второй URL-адрес), он должен добавить амперсанд « &
» вместо вопросительного знака « ?
» Перед « utm=some...
»
В конечном счете это изменит только URL-адреса для domain me.com.
Это немного сложно, но следующий код должен работать, если ваши URL-адреса заключены в кавычки (одиночные или двойные). Он также будет обрабатывать идентификаторы фрагментов (например, #section-2
).
$url_modifier = 'utm=some&medium=stuff'; $url_modifier_domain = preg_quote('www.me.com'); $html_text = preg_replace_callback( '#((?:https?:)?//'.$url_modifier_domain.'(/[^\'"\#]*)?)(?=[\'"\#])#i', function($matches){ global $url_modifier; if (!isset($matches[2])) return $matches[1]."/?$url_modifier"; $q = strpos($matches[2],'?'); if ($q===false) return $matches[1]."?$url_modifier"; if ($q==strlen($matches[2])-1) return $matches[1].$url_modifier; return $matches[1]."&$url_modifier"; }, $html_text);
Входные данные:
<a href="http://www.me.com">Lorem</a> <a href="http://www.me.com/">ipsum</a> <a href="http://www.me.com/#section-2">dolor</a> <a href="http://www.me.com/path-to-somewhere/file.php">sit</a> <a href="http://www.me.com/?">amet</a>, <a href="http://www.me.com/?foo=bar">consectetur</a> <a href="http://www.me.com/?foo=bar#section-3">elit</a>.
Вывод:
<a href="http://www.me.com/?utm=some&medium=stuff">Lorem</a> <a href="http://www.me.com/?utm=some&medium=stuff">ipsum</a> <a href="http://www.me.com/?utm=some&medium=stuff#section-2">dolor</a> <a href="http://www.me.com/path-to-somewhere/file.php?utm=some&medium=stuff">sit</a> <a href="http://www.me.com/?utm=some&medium=stuff">amet</a>, <a href="http://www.me.com/?foo=bar&utm=some&medium=stuff">consectetur</a> <a href="http://www.me.com/?foo=bar&utm=some&medium=stuff#section-3">elit</a>.
Это тривиальная задача, использующая DOMDocument
:
$html_text = 'Lorem ipsum <a href="http://www.me.com">dolor sit</a> amet, <a href="http://www.me.com/page.php?id=10">consectetur</a> elit.'; $html = new DOMDocument(); $html->loadHtml($html_text); foreach ($html->getElementsByTagName('a') as $element) { $href = $element->getAttribute('href'); if (!empty($href)) // only edit the attribute if it's set { // check if we need to append with ? or & if (strpos($href, '?') === false) $href .= '?'; else $href .= '&'; // append querystring $href .= 'utm=some&medium=stuff'; // set attribute $element->setAttribute('href', $href); } } // output altered code echo $html->C14N();
Сценарий : http://phpfiddle.org/lite/code/wvq-ujk
Вы можете добиться этого, используя preg_replace
, 2 шаблона и два replacememts:
<?php $add = "utm=some&medium=stuff"; $patterns = array( '/(https?:\/\/(?:www)?me\.com(?=.*?\?)[^"]*)/', # positive lookahead to check if there is a ? mark in url '/(https?:\/\/(?:www)?me\.com(?!.*?\?)[^"]*)/' # negative lookahead to check if ? mark is not in ); $replacements = array( "$1&".$add, # replacement if first pattern take place '$1?'.$add # replacement if second pattern take place ); $str = 'Lorem ipsum <a href="http://www.me.com">dolor sit</a> amet, <a href="http://www.me.com/page.php?id=10">consectetur</a> elit.'; $str = preg_replace($patterns, $replacements, $str); echo $str; /* Output: Lorem ipsum <a href="http://www.me.com&utm=some&medium=stuff">dolor sit</a> amet, <a href="http://www.me.com/page.php?id=10&utm=some&medium=stuff">consectetur</a> elit. */ ?>
Мне понравились другие ответы с использованием DOM-решений, затем я тестировал время, которое каждый фрагмент принимает для следующего ввода:
<a href="http://www.me.com">Lorem</a> <a href="http://www.me.com/">ipsum</a> <a href="http://www.me.com/#section-2">dolor</a> <a href="http://www.me.com/path-to-somewhere/file.php">sit</a> <a href="http://www.me.com/?">amet</a>, <a href="http://www.me.com/?foo=bar">consectetur</a> <a href="http://www.me.com/?foo=bar#section-3">elit</a>.
С microtime
:
$ts = microtime(true); // codes printf("%.10f\n", microtime(true) - $ts);
Чтобы вы могли видеть их ниже (мс):
@squeamish ossifrage: 0.0001089573 @Cobra_Fast: 0.0003509521 @Emissary: 0.0094890594 @Me: 0.0000669956
Это было интересно для меня, RegEx
es хорошо.
Если вы хотите отвлечь все неприятные парсинга от своего скрипта, вы всегда можете использовать парсер DOM, которого есть много . В этом примере я выбрал Simple HTML-DOM, поскольку это единственный, с которым я действительно знаком (это, по общему признанию, не самая эффективная библиотека, но вы не делаете ничего интенсивного).
include 'simple_html_dom.php'; $html = str_get_html($htmlString); foreach($html->find('a') as $a){ $url = strtolower($a->href); if( strpos($url, 'http://me.com') === 0 || strpos($url, 'http://www.me.com') === 0 || strpos($url, 'http://') !== 0 // local url ){ $url = explode('?', $url, 2); if(count($url)<2) $qry = array(); else parse_str($url[1], $qry); $qry = array_merge($qry, array( 'utm' => 'some', 'medium' => 'stuff' )); $parts = array(); foreach($qry as $key => $val) $parts[] = "{$key}={$val}"; $a->href = sprintf("%s?%s", $url[0], implode('&', $parts)); } } echo $html;
В этом примере я предположил, что me.com – ваш веб-сайт и что местные пути также должны быть квалифицированы. Я также предполагаю, что строки запроса, вероятно, будут простыми ключами: пары значений . В текущей форме, если URL уже имеет один из ваших параметров запроса, он переписан. Если вы хотите сохранить существующие значения, вам нужно будет поменять порядок параметров в функции array_merge
.
<a href="http://me.com/">test</a> <a href="http://WWW.me.com/">test</a> <a href="local.me.com.php">test</a> <a href="http://notme.com">test</a> http://me.com/not-a-link <a href="http://me.com/?id=10&utm=bla">test</a>
<a href="http://me.com/?utm=some&medium=stuff">test</a> <a href="http://www.me.com/?utm=some&medium=stuff">test</a> <a href="local.me.com.php?utm=some&medium=stuff">test</a> <a href="http://notme.com">test</a> http://me.com/not-a-link <a href="http://me.com/?id=10&utm=some&medium=stuff">test</a>
Если у вас есть проблемы с DOMDocument и utf8, попробуйте выполнить следующее:
$html_text = '<p>This is a text with speical chars ÄÖÜ <a href="http://example.com/This-is-my-Page" target="_self">here</a>.</p>'; $html_text .= '<p>continue</p>'; $html = new DOMDocument('1.0', 'utf-8'); // Set charset-header for DOMDocument $html_prepared = '<html>' . '<head>' . '<meta http-equiv="content-type" content="text/html; charset=UTF-8">' . '</head>' . '<body>' . '<div>' . $html_text . '</div>' . '</body>'; $html->loadHtml($html_prepared); foreach ($html->getElementsByTagName('a') as $element) { $href = $element->getAttribute('href'); if (!empty($href)) // only edit the attribute if it's set { // check if we need to append with ? or & if (strpos($href, '?') === false) $href .= '?'; else $href .= '&'; // append querystring $href .= 'utm=some&medium=stuff'; // set attribute $element->setAttribute('href', $href); } } // 1) Remove doctype-declaration $html->removeChild($html->firstChild); // 2) Remove head $html->firstChild->removeChild($html->firstChild->firstChild); // 3) Only keep body's first Child $html->replaceChild($html->firstChild->firstChild->firstChild, $html->firstChild); print $html->saveHTML();