获取两个字符串之间的内容 PHP

33

如何最好地获取两个字符串之间的内容,例如:

ob_start();
include('externalfile.html'); ## see below
$out = ob_get_contents();
ob_end_clean();

preg_match('/{FINDME}(.|\n*)+{\/FINDME}/',$out,$matches);
$match = $matches[0];

echo $match;

## I have used .|\n* as it needs to check for new lines. Is this correct?

## externalfile.html

{FINDME}
Text Here
{/FINDME}

因为某种原因,这似乎在我的代码中的一个地方起作用,而在另一个地方则不起作用。我这样做对吗?还是有更好的方法?

此外,使用输出缓冲区是做这件事的方式,还是使用file_get_contents?

提前感谢!


如果它在某些情况下有效而在其他情况下无效,您应该提供它有效和无效的示例。 - Welbog
7个回答

52

你可以使用substr和strpos来实现这个功能。

$startsAt = strpos($out, "{FINDME}") + strlen("{FINDME}");
$endsAt = strpos($out, "{/FINDME}", $startsAt);
$result = substr($out, $startsAt, $endsAt - $startsAt);

您需要添加错误检查来处理无法找到 FINDME 的情况。


1
这只会找到一个匹配。 - 472084
1
@472084 是的,但你可以编写一个包装函数,在 while 循环或递归中执行此代码。这个答案是一个非常好的基础。 - Liglo App

50
  • 使用#而不是/,这样就不需要转义它们。

  • modifier s允许.匹配换行符。

  • {可能是{n}{n,m}量词的开始。结束的}没有特殊含义,但转义它不会导致错误。

  • 基本的

    preg_match('#\{FINDME}(.+)\{/FINDME}#s', $out, $matches);
  • 高级的用于各种标签等(通过JavaScript的样式不太好看)。

    $delimiter = '#';
    $startTag = '{FINDME}';
    $endTag = '{/FINDME}';
    $regex = $delimiter . preg_quote($startTag, $delimiter) 
                      . '(.*?)' 
                      . preg_quote($endTag, $delimiter) 
                      . $delimiter 
                      . 's';
    preg_match($regex,$out,$matches);
将这段代码放入一个函数中
  • 对于任何你不想执行任何“杂乱”的 PHP 代码的文件,你应该使用 file_get_contents。include/require 在这里甚至不应该是一个选项。

3
我敢打赌{FINDME}只是为了举例。 - Cem Kalyoncu
无法工作(没有输出),不知道为什么...我的开始标签:src=¦我的结束标签:¦ - Jonny
这是一个很好的解决方案。通过添加U(ungreedy)修饰符(#sU),可以使用多个相同的搜索标签实例。 - Eric P

8

如果可能的话,我喜欢避免使用正则表达式。以下是一种获取两个字符串之间所有字符串并返回数组的替代方案。

function getBetween($content, $start, $end) {
    $n = explode($start, $content);
    $result = Array();
    foreach ($n as $val) {
        $pos = strpos($val, $end);
        if ($pos !== false) {
            $result[] = substr($val, 0, $pos);
        }
    }
    return $result;
}
print_r(getBetween("The quick brown {{fox}} jumps over the lazy {{dog}}", "{{", "}}"));

结果:

Array
(
    [0] => fox
    [1] => dog
)

5

我喜欢这两种解决方案

function GetBetween($content,$start,$end)
{
    $r = explode($start, $content);
    if (isset($r[1])){
        $r = explode($end, $r[1]);
        return $r[0];
    }
    return '';
}


function get_string_between($string, $start, $end){
    $string = " ".$string;
    $ini = strpos($string,$start);
    if ($ini == 0) return "";
    $ini += strlen($start);   
    $len = strpos($string,$end,$ini) - $ini;
    return substr($string,$ini,$len);
}

我也对这两个方案进行了一些基准测试,结果两者所需的时间几乎相同。您也可以进行测试。我给了两个函数一个文件进行读取,该文件包含约60000个字符(使用Ms. Word的字数统计进行审核),两个函数的查找结果均为大约0.000999秒。

$startTime = microtime(true);
GetBetween($str, '<start>', '<end>');
echo "Explodin Function took: ".(microtime(true) - $startTime) . " to finish<br />";

$startTime = microtime(true);
get_string_between($str, '<start>', '<end>');
echo "Subsring Function took: ".(microtime(true) - $startTime) . " to finish<br />";

这很棒。它能否被改进以查找多个匹配项?因此返回一个包含所有匹配项的数组? - Drew Baker

1

换行符可能会导致正则表达式出现问题,尝试在处理之前删除或替换它们为 \n。


将字符串进行变异以使正则表达式模式能够工作通常意味着该正则表达式模式设计不良。不要责怪字符串,而是要责怪模式。 - mickmackusa

0
这是一个PHP解决方案,它返回在干草堆中标签之间找到的字符串。它可以工作,但我还没有测试其效率。我需要这个并受到了Adam Wright在此页面上的回答的启发。
返回一个包含所有在$haystack中$tag和$end_symbol.$tag之间找到的字符串的数组(),如果没有找到$end_symbol.$tag,则返回FALSE,因此在$haystack中不存在标签对。
function str_between_tags($haystack, $tag, $end_symbol){
    $c_end_tags = substr_count($haystack, $end_symbol.$tag);
    if(!$c_end_tags) return FALSE;

    for($i=0; $i<$c_end_tags; $i++){
        $p_s = strpos($haystack, $tag, (($p_e)?$p_e+strlen($end_symbol.$tag):NULL) ) + strlen($tag );
        $p_e = strpos($haystack, $end_symbol.$tag, $p_s);
        $result[] = substr($haystack, $p_s, $p_e - $p_s);
    }
    return $result;
}

-1

将所有内容合并为一个字符串的快速方法。

$newlines = array("\t","\n","\r","\x20\x20","\0","\x0B");
$one_string = str_replace($newlines, "", html_entity_decode($content));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接