我正在编写一个脚本,用于从网络设备解析日志文件。从设备生成的日志文件不是规则的,行不遵循逻辑序列,并且具有多个模式。我的脚本需要从日志行中只提取与特定模式匹配的行,并从该行中提取字符串中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() failn";
}
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 = '/((?:[^/][dw.-]+)(?<=%extensions%))/';
正如您所看到的,我使用占位符作为文件扩展名,因为在这种情况下,我需要通过配置或数据库查询来动态设置它们。接下来,我对照第一个图案验证每个提取的线
/**
* Line extract
*
* @param string $file_line File line string
*
* @return array An array if matches
* Array (
* [0] => Matched line
* [1] => DateTime 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]);
希望能帮助别人。谢谢