PHP中的通配符替换

时间:2009-11-29 17:01:23

标签: php regex

我没有在PHP中使用正则表达式的经验,所以我通常使用一系列str_replace(),substr(),strpos(),strstr()等编写一些复杂的函数(你明白了)。

这次我想要正确地执行此操作,我知道我需要使用正则表达式,但我对使用什么(ereg或preg)以及语法应该是多么困惑。

注意:我没有解析HTML或XML,有时我会使用除(例如,|或〜或[tag]或::)之外的分隔符。我正在寻找一种使用正则表达式在两个已知分隔符之间进行通配符替换的通用方法,我没有构建HTML或XML解析器。

我需要的是一个取代它的正则表达式:

<sometag>everything in here</sometag>

用这个:

<sometag>new contents</sometag>

我已经在线阅读了一些文档,但我很困惑,希望你们中的一位正则表达式专家能够提供一个简单的解决方案。我怀疑我会将值传递给函数,如下所示:

$new_text = swapText ( "<sometag>", $the_new_text_to_go_into_the_dag );

function swapText ( $in_tag_with_brackets_to_update, $in_new_text ) {
 // define tags
 $starting_tag  = $in_tag_with_brackets_to_update;
 $ending_tag    = str_replace( "<", "</", $in_tag_with_brackets_to_update) );

 // not sure if this is the proper regex match string or not
 // and/or if any escaping needs to be done on the tags
 $find_string         = "{$starting_tag}.*{$ending_tag}";
 $replace_with_string = "{$starting_tag}{$in_new_text}{$ending_tag}";

 // after some regex, this function should return new version of <tag>data</tag>
}

感谢。

4 个答案:

答案 0 :(得分:10)

你说你不打算解析xml,然后继续展示一个xml示例。这有点令人困惑。

现在,你不能使用正则表达式解析xml的原因是它们不是上下文的。因此,存在一类不能用于正则表达式的问题。这包括嵌套标签(无论它们是否为xml),因此请记住这一点。

这样,你应该使用preg - 而不是eregereg是一种较少使用,较慢且现已弃用的正则表达式。别忘了。

在pcre(Perl Compatible Regular Expressions)中,这是preg使用的语言,.(点)是一个通配符,匹配任何单个字符(新行除外)。你可以在比赛后放一个量词。量词可以是明确的数字范围,例如{1,3}(表示至少一个,但最多3个),或者您可以使用其中一个简写符号,例如+({的缩写} {1}},意思是至少一个)或{1,}(意思是任何数字,包括零)。有了这些知识,您可以使用*匹配任何内容。

默认情况下,表达式将匹配最大可能模式(称为贪婪)。您可以使用.*修饰符更改此设置。因此?将匹配任何内容,但采用最短的模式。然后可以使用它来匹配任何分隔值,如下所示:

.*?

请注意,我在这里使用~<foo>.*?</foo>~ 作为分隔符,以避免在表达式中转义~。标准是使用/作为分隔符,在这种情况下表达式将如下所示:

/

一般来说,上面的做法是不好的,因为匹配一个否定的字符类比一个点要好得多,但为了让事情变得简单,只要忽略这一点,直到你掌握了基础知识。它在大多数情况下都有效。特别是,由于/<foo>.*?<\/foo>/ 与换行符不匹配,如果内容包含换行符,则无效。如果需要,可以执行以下两种操作之一:向表达式添加modifier,或者将.替换为包含换行符的字符类。例如.(表示空白字符非空白字符,与任何内容相同)。这就是表达式的外观:

[\s\S]

或者:

~<foo>.*?</foo>~s

为了使所有这些工作,让我们将其传递给~<foo>[\s\S]*?</foo>~ 函数:

preg_replace

如果您的标记名称是可变的,则可以像使用SQL查询一样构建表达式。就像SQL一样,你需要转义某些字符。请使用echo preg_replace('~<foo>.*?</foo>~s', '<foo>Lorem Ipsum</foo>', $input);

preg_quote

答案 1 :(得分:3)

@OP,如果您的任务非常简单,则无需使用复杂的正则表达式或解析器。一个例子,只是使用正常的子串....

$mystr='<sometag>everything in here</sometag>';
$start=strpos($mystr,"<sometag>");
$end=strpos($mystr,"</sometag>");
print substr($mystr,0,$start+strlen("<sometag>") ) . "new value" . substr($mystr,$end);

答案 2 :(得分:1)

首先,如果是替换的html,请使用simple html dom之类的内容。如果格式与您说的完全相同(例如,<sometag>不能为<sometag >),则可以使用正则表达式。

不要使用基于ereg的函数,因为它们已被弃用,请使用preg函数。

preg_replace('%(<sometag>)[^<]*(</sometag>)%i', '$1something else$2', $str);

修改
上面稍微好一点的版本,现在支持在文本

中有<
preg_replace('%(<sometag>).*?(</sometag>)%i', '$1something else$2', $str);

$ 1和$ 2是括号内的匹配文本。由于这些是常数,它们可以用常数

代替
preg_replace('%<sometag>.*?</sometag>%i', '<sometag>something else</sometag>', $str);

答案 3 :(得分:0)

我编写了以下函数来通过通配符替换部分字符串:

function wildcardReplace($String,$Search,$Filler,$Wildcard = '???'){

        list($startStr,$endStr) = explode($Wildcard,$Search);

        $start = strpos($String,$startStr);

        // Make sure the end point is the first closest match after the start string.   

        $endofstarter = strpos($String,$startStr) + strlen($startStr);

        $startofender = strpos(
                    substr($String,$endofstarter),
                    $endStr
                ) + $endofstarter;


        $Result = substr($String,0,$start+strlen($startStr) ) . $Filler. substr($String,$startofender);

        // Replace any remaining stuff

        $RemainingString = substr($String,$startofender);

        // If theres any matches left, replace them

        if(strpos($RemainingString,$startStr)>-1) $Result = str_replace($RemainingString,wildcardReplace($RemainingString,$Search,$Filler),$Result);

        return $Result;
}

使用示例:$Output = wildcardReplace('<a href="http://www.youtube.com/watch?v=dQw4w9WgXcQ"><img src="rickroll.png" width="500"></a>','width="???"',350,'???')