使用PHP PCRE regex从日志字符串上的url获取扩展名


Get filename with extension from url on log string using PHP PCRE regex

我正在编写一个脚本,用于从网络设备解析日志文件。从设备生成的日志文件不是规则的,行不遵循逻辑序列,并且具有多个模式。我的脚本需要从日志行中只提取与特定模式匹配的行,并从该行中提取字符串中url的日期时间、条目类型、资源类型和资源名称等特定信息。我需要匹配的模式如下:

dd-mm-yyyy hh:mm:ss INFO spx.resource.media-新资源"URI"[标志](dlc/tcd)

其中"INFO"是条目类型,"spx.resource.media"是资源类型,URI中包含资源名称。目前,我们需要过滤那些有特定扩展的。

我复习了几篇关于这个主题的帖子,并使用了这个在线工具:

/('d{2}-'d{2}-'d{4}'s{1}'d{2}:'d{2}:'d{2})'s{1,}('w{4})'s{1,}(spx.resource.media)(.{1,}(?<=(?:.jpg)|(?:.png)))/g

问题是,最后一个regex组匹配整个URI加上资源类型中的字符和空格,y只需要带扩展名的文件名。我尝试了这个"regex-to-get-a-filename-from-a-url"(无法发布信誉不足的链接),但没有锻炼,因为调试器将^/标记为未标记的分隔符。如果移除也不起作用。日志的一部分可以在这里找到。我真的需要得到这个。

感谢您阅读和/或回答

看看这个。首先识别文件的位置,然后您可以相应地循环以获得您想要的

<?php
$handle = @fopen("/tmp/inputfile.txt", "r");
if ($handle) {
while (($buffer = fgets($handle, 4096)) !== false) {
    echo $buffer;
}
if (!feof($handle)) {
    echo "Error: unexpected fgets() fail'n";
}
fclose($handle);
}
?>

一个月前,A带来了一个解决方案。我想要的是用一种模式提取文件名和其他子组,我不知道这是否可能,但以我目前的正则表达式技能来说是不可能的。因此,我所做的是使用三种正则表达式模式,正如您在下面的代码中所看到的:

这段代码是我(显然)称为Parser的类的一部分。首先,我将模式定义为类中的常量。

/**
 * @const string Log line pattern
 */
const LINE_REGEX_PATTERN = '/('d{2}-'d{2}-'d{4}'s{1}'d{2}:'d{2}:'d{2})'s{1,}('w{4})'s{1,}(spx.resource.media)(.{1,}(?<=%extensions%))/';
/**
 * @const string Full URL pattern
 */
const FULL_URL_PATTERN = '/'b((?:https?|ftps?|file|spx):'/'/[-A-Z0-9+&@#'/%?=~_|$!:,.;]*[A-Z0-9+&@#'/%=~_|$])/i';
/**
 * @const string Filename pattern
 */
const RESOURCE_REGEX_PATTERN = '/((?:[^'/]['d'w'.-]+)(?<=%extensions%))/';

正如您所看到的,我使用占位符作为文件扩展名,因为在这种情况下,我需要通过配置或数据库查询来动态设置它们。接下来,我对照第一个图案验证每个提取的线

/**
 * Line extract
 *
 * @param string $file_line File line string
 *
 * @return array An array if matches
 *               Array (
 *                  [0] => Matched line
 *                  [1] => Date'Time subgroup (format >> d-M-y H:i:s)
 *                  [2] => String flag subgroup
 *                  [3] => Resource type subgroup (not used)
 *                  [4] => Text string containing resource URL
 *               )
 *               , null otherwise
 *
 * @throws RegexException If malformed pattern
 */
private function extractMatches($file_line)
{
    $extensions = array();
    // build valid extensions subgroup
    foreach ($this->valid_extensions as $extension) {
        $extensions[] = sprintf("(?:'.%s)", $extension);
    }
    $matches = array();
    // replace extensions placeholder
    $pattern  = str_replace('%extensions%', implode('|', $extensions), self::LINE_REGEX_PATTERN);
    $is_valid = preg_match($pattern, $file_line, $matches);
    if ($is_valid === false) {
        throw new RegexException();
    }
    return $matches;
}

从得到的数组(如果有的话)中,我获取第五个元素(存储带有URL的文本的元素),然后我传递给另外两个函数,第一个用于完整的URL提取,第二个用于最终提取文件名。见下文:

/**
 * Full URL extract
 *
 * @param string $text Text with URL in it
 *
 * @return string The URL, empty string otherwise
 *
 * @throws RegexException If malformed pattern
 */
private function extractUrl($text)
{
    $match    = array();
    $is_valid = preg_match(self::FULL_URL_PATTERN, $text, $match);
    if ($is_valid === false) {
        throw new RegexException();
    } elseif ($is_valid === 1) {
        return $match[0];
    }
    return ''; // No URL found!
}
/**
 * Filename extract
 *
 * @param string $url Resource URL (expects no GET parameters)
 *
 * @return string Resource filename (includes extension), empty string otherwise
 *
 * @throws RegexException If malformed pattern
 */
private function extractResourceNameFromUrl($url)
{
    $extensions = array();
    // build valid extensions subgroup
    foreach ($this->valid_extensions as $extension) {
        $extensions[] = sprintf("(?:'.%s)", $extension);
    }
    $matches = array();
    // replace extensions placeholder
    $pattern  = str_replace('%extensions%', implode('|', $extensions), self::RESOURCE_REGEX_PATTERN);
    $is_valid = preg_match($pattern, $url, $matches);
    if ($is_valid === false) {
        throw new RegexException();
    } elseif ($is_valid === 1) {
        return $matches[1];
    }
    return '';
}

最后,在我的应用程序中,我刚刚做了一些事情:

$parser = new Parser();
// fetch file line loop
$matches = $parser->extractMatches($file_line);
$url = $parser->extractUrl($matches[4]);
$filename = $parser->extractResourceNameFromUrl($matches[4]);

希望能帮助别人。谢谢