【问题标题】:preg_match_all on remote contentpreg_match_all 远程内容
【发布时间】:2017-02-10 08:51:07
【问题描述】:

我尝试解析 iCal:

//打开文件 $calendar = file_get_contents('http://app.kigo.net/public/ics.php?c-7ca2eb67c1a7fa8b87b2434ed1096076-422-9871b35967bb29f999cd11ac72943011'); //调试目的 回声$日历; //解析字符串 preg_match_all('#^BEGIN\:VEVENT.*?END\:VEVENT$#sm',$calendar,$results,PREG_SET_ORDER); //输出:空! 打印_r($结果);

它返回一个空数组。

无论如何,如果我将“$calendar”内容复制/粘贴到另一个变量上,并使用相同的正则表达式对其进行解析,它就可以正常工作。

为什么当我直接从 file_get_contents 调用 同一字符串 上的 preg_match_all 时,它会出错?

【问题讨论】:

  • URI 是否返回具有正确文件头的文件?甚至内容。尝试将内容回显到页面中。
  • 首先 print_r 你的 $calandar 并检查是否为空或假
  • 我得到类似 failed to open stream: php_network_getaddresses: getaddrinfo failed
  • file_get_contents() 现在应该发出警告
  • 我用所有代码编辑了消息。在我的电脑和服务器上,“内容”变量包含正确的内容(日历)。正则表达式返回一个空数组。相同的字符串,(复制/粘贴),相同的 regex = 数组包含日历的所有事件。

标签: php regex file-get-contents


【解决方案1】:

远程文件使用序列 CR LF 作为换行符,这就是锚$ 不匹配的原因。当您将文件内容复制/粘贴到(或从)默认情况下仅使用 LF 作为换行符的应用程序时,序列 CR LF 可能会默默地替换为 LF 并且您的模式有效。

解决问题的几种方法:

1) 在你的模式中明确写回车:

#^BEGIN:VEVENT.*?END:VEVENT\r$#sm

如果您不想在匹配结束时回车,请使用trim 或将其放入前瞻断言中:#^BEGIN:VEVENT.*?END:VEVENT(?=\r$)#sm。 您还可以删除$ 并使用与\r\r\n\n 匹配的\R 别名。

2) 允许$ 使用指令(*ANYCRLF) 匹配任何换行符序列

#(*ANYCRLF)^BEGIN:VEVENT.*?END:VEVENT$#sm

3) 根本不要使用模式 (毕竟你只是在固定行之间寻找块,如果你的文件可能有点长,它会更优雅并节省内存来读取你的文件行并使用生成器返回块)

$filePath = 'http://app.kigo.net/public/ics.php?c-7ca2eb67c1a7fa8b87b2434ed1096076-422-9871b35967bb29f999cd11ac72943011';

try {
    if ( false === $fp = fopen($filePath, 'rb') )
        throw new Exception('Could not open the file!');

} catch (Exception $e) {
    echo 'Error (File: ' . $e->getFile() . ', line ' . $e->getLine() . '): ' . $e->getMessage();
}

foreach (genBlocks($fp, "BEGIN:VEVENT\r\n", "END:VEVENT\r\n") as $block) {
    echo $block . PHP_EOL;
}

fclose($fp);

function genBlocks($fp, $start, $end, $buffer = 1024) {
    $block = false;
    while ( false !== $line = fgets($fp, $buffer) ) {
        if ( $line === $start ) {
            $block = $line;
        } elseif ( $block !== false ) {
            $block .= $line;
            if ( $line === $end ) {
                yield $block;
                $block = false;
            }
        }
    }
}

注意:您也可以使用stream_get_line 代替fgets,因为它能够返回没有换行序列的行。

【讨论】:

  • 使用第二个解决方案 (*ANYCRLF) 我解决了所有问题!非常感谢!
猜你喜欢
  • 1970-01-01
  • 2016-07-16
  • 1970-01-01
  • 1970-01-01
  • 2010-10-02
  • 2016-11-14
  • 2014-05-04
  • 2013-04-04
  • 1970-01-01
相关资源
最近更新 更多