2

我有以下内容:

$reg[0] = '`<a(\s[^>]*)href="([^"]*)"([^>]*)>`si';
$reg[1] = '`<a(\s[^>]*)href="([^"]*)"([^>]*)>`si';
$replace[0] = '<a$1href="http://www.yahoo.com"$3>';
$replace[1] = '<a$1href="http://www.live.com"$3>';
$string = 'Test <a href="http://www.google.com">Google!!</a>Test <a href="http://www.google.com">Google!!2</a>Test';
echo preg_replace($reg, $replace, $string);

结果是:

Test <a href="http://www.live.com">Google!!</a>Test <a href="http://www.live.com">Google!!2</a>Test

我希望最终得到(不同之处在于第一个链接):

Test <a href="http://www.yahoo.com">Google!!</a>Test <a href="http://www.live.com">Google!!2</a>Test

这个想法是用唯一的其他 URL 替换字符串内链接中的每个 URL。这是一个通讯系统,我想跟踪人们点击了什么,所以 URL 将是一个“假” URL,在记录点击后他们将被重定向到真实 URL。

4

4 回答 4

2

问题是您的第一个替换字符串将与第二个搜索模式匹配,有效地用第二个替换字符串覆盖第一个替换字符串。

除非您能以某种方式将“修改过的”链接与原始链接区分开来,以免它们被其他表达式捕获(也许通过添加额外的 HTML 属性?),否则我认为您无法真正通过一次preg_replace()调用来解决这个问题. 想到的一种可能的解决方案(除了正则表达式中的差异)是使用preg_match_all(),因为它会给你一个匹配的数组来使用。然后,您可以通过遍历数组并str_replace()在每个匹配的 URL 上运行 a 来使用跟踪 URL 对匹配的 URL 进行编码。

于 2009-04-18T07:34:21.140 回答
1

I do not know, if I'd understood it right. But I'd written following snippet: The regex matches some hyperlinks. Then it loops thru the result and compares the text nodes against the hyperlink references. When a text node is found in a hyperlink reference, then it extends the matches by inserting a trackback sample link with a unique key.

UPDATE The snippets finds all hyperlinks:

  1. find links
  2. build track back link
  3. find position of each found link (matches[3]) and set a template tag
  4. replace templatetags by trackback links Each link position is unique.

$string = '<h1>Newsletter Name</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis, ligula <a href="http://bar.com">sed sollicitudin</a> dignissim, lacus dolor suscipit sapien, <a href="http://foo.com">bar.com</a> ipsum ligula non tortor. Quisque sagittis sodales elit. Mauris dictum blandit lacus. Mauris consequat <a href="http://last.fm">laoreet lacus</a>.</p> <h1>Newsletter Name</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis, ligula <a href="http://bar.com">sed sollicitudin</a> dignissim, lacus dolor suscipit sapien, <a href="http://foo.com">bar.com</a> ipsum ligula non tortor. Quisque sagittis sodales elit. Mauris dictum blandit lacus. Mauris consequat <a href="http://last.fm">laoreet lacus</a>.</p> <h1>Newsletter Name</h1> <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis, ligula <a href="http://bar.com">sed sollicitudin</a> dignissim, lacus dolor suscipit sapien, <a href="http://foo.com">bar.com</a> ipsum ligula non tortor. Quisque sagittis sodales elit. Mauris dictum blandit lacus. Mauris consequat <a href="http://last.fm">laoreet lacus</a>.</p> ';

$regex = '<[^>]+>(.*)<\/[^>]+>';
preg_match_all("'<a\s+href=\"(.*)\"\s*>(.*)<\/[^>]+>'U",$string,$matches);


$uniqueURL = 'http://www.yourdomain.com/trackback.php?id=';

foreach($matches[2] as $k2 => $m2){
    foreach($matches[1] as $k1 => $m1){
        if(stristr($m1, $m2)){
                $uniq = $uniqueURL.md5($matches[0][$k2])."_".rand(1000,9999);
                $matches[3][$k1] = $uniq."&refLink=".$m1;
        }
    }
}


foreach($matches[3] as $key => $val) {

    $startAt = strpos($string, $matches[1][$key]);
    $endAt= $startAt + strlen($matches[1][$key]);

    $strBefore = substr($string,0, $startAt);
    $strAfter = substr($string,$endAt);

    $string = $strBefore . "@@@$key@@@" .$strAfter;

}
foreach($matches[3] as $key => $val) {
        $string = str_replace("@@@$key@@@",$matches[3][$key] ,$string);
}
print "<pre>";
echo $string;
于 2009-04-19T09:43:35.267 回答
1

我不擅长正则表达式,但如果你正在做的只是用一个跟踪点击并重定向用户的内部 URL 替换外部 URL(即不是你的站点/应用程序的一部分),那么它应该很容易构造一个仅匹配外部 URL 的正则表达式。

因此,假设您的域是foo.com,那么您只需要创建一个正则表达式,它只匹配不包含以 . 开头的 URL 的超链接http://foo.com。现在,正如我所说,我对正则表达式很不好,但这是我最好的尝试:

$reg[0] = '`<a(\s[^>]*)href="(?!http://foo.com)([^"]*)"([^>]*)>`si';

编辑:如果您还想跟踪对内部 URL 的点击,那么只需替换http://foo.com为您的重定向/跟踪页面的 URL,例如http://foo.com/out.php.

我将通过一个示例场景来说明我在说什么。假设您有以下时事通讯:

<h1>Newsletter Name</h1>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec lobortis,
ligula <a href="http://bar.com">sed sollicitudin</a> dignissim, lacus dolor
suscipit sapien, <a href="http://foo.com">eget auctor</a> ipsum ligula
non tortor. Quisque sagittis sodales elit. Mauris dictum blandit lacus.
Mauris consequat <a href="http://last.fm">laoreet lacus</a>.</p>

出于本练习的目的,搜索模式将是:

// Only match links that don't begin with: http://foo.com/out.php
`<a(\s[^>]*)href="(?!http://foo.com/out\.php)([^"]*)"([^>]*)>`si

这个正则表达式可以分解为 3 个部分:

  1. <a(\s[^>]*)href="
  2. (?!http://foo.com/out\.php)([^"]*)
  3. "([^>]*)>

在搜索的第一遍,脚本将检查:

<a href="http://bar.com">

此链接满足正则表达式的所有 3 个组件,因此 URL 存储在数据库中并替换为http://foo.com/out.php?id=1.

在搜索的第二遍中,脚本将检查:

<a href="http://foo.com/out.php?id=1">

此链接匹配 1 和 3,但不匹配 2。因此搜索将转到下一个链接:

<a href="http://foo.com">

此链接满足正则表达式的所有 3 个组件,因此 URL 存储在数据库中并替换为http://foo.com/out.php?id=2.

在搜索的第 3 遍中,脚本将检查前 2 个(已替换)链接,跳过它们,然后找到与时事通讯中最后一个链接的匹配项。

于 2009-04-18T08:46:27.957 回答
0

Until PHP 5.3 where you can just create a function on the spot, you have to use either create_function (which I hate) or a helper class.

/**
 * For retrieving a new string from a list.
 */
class StringRotation {
    var $i = -1;
    var $strings = array();

    function addString($string) {
        $this->strings[] = $string;
    }

    /**
     * Use sprintf to produce result string
     * Rotates forward
     * @param array $params the string params to insert
     * @return string
     * @uses StringRotation::getNext()
     */
    function parseString($params) {
        $string = $this->getNext();
        array_unshift($params, $string);
        return call_user_func_array('sprintf', $params);
    }

    function getNext() {
        $this->i++;
        $t = count($this->strings);
        if ($this->i > $t) {
            $this->i = 0;
        }
        return $this->strings[$this->i];
    }

    function resetPointer() {
        $this->i = -1;
    }
}

$reg = '`<a(\s[^>]*)href="([^"]*)"([^>]*)>`si';
$replaceLinks[0] = '<a%2$shref="http://www.yahoo.com"%4$s>';
$replaceLinks[1] = '<a%2$shref="http://www.live.com"%4$s>';

$string = 'Test <a href="http://www.google.com">Google!!</a>Test <a href="http://www.google.com">Google!!2</a>Test';

$linkReplace = new StringRotation();
foreach ($replaceLinks as $replaceLink) {
    $linkReplace->addString($replaceLink);
}

echo preg_replace_callback($reg, array($linkReplace, 'parseString'), $string);
于 2009-04-19T20:56:26.493 回答