在字符串中查找无界文件路径
本文关键字:文件 路径 查找 字符串 | 更新日期: 2023-09-27 18:09:46
我有这些由封闭源第三方软件生成的错误信息,我需要从中提取文件路径。
所述文件路径为:
- 没有边界(即没有被引号、圆括号、括号等包围)
- root(即从
<letter>:'
开始,如C:'
) - 不保证有文件扩展名
- 表示保证存在于运行提取代码的计算机上的文件(仅文件,而不是目录)。
- 由任何有效字符组成,包括空格,使它们难以被发现(例如
C:'This'is a'path 'but what is an existing file path here
)
需要注意的是,每条消息可以有0个或多个文件路径。
如何在错误信息中找到这些文件路径?
我在下面给出了一个答案,但我感觉有更好的方法来解决这个问题。
对于每个匹配,期待下一个'''字符。所以你可能会得到"c:'mydir'"。检查该目录是否存在。然后找到下一个'
,给出"c:'mydir'subdir"。检查该路径。最终你会找到一条不存在的路径,或者你会到达下一场比赛的开始。
这时,您就知道要在哪个目录中查找了。然后调用Directory.GetFiles
并匹配与子字符串匹配的最长文件名,子字符串从您找到的最后一个路径开始。
这样可以减少回溯。
这是如何做到的:
static void FindFilenamesInMessage(string message) {
// Find all the "letter colon backslash", indicating filenames.
var matches = Regex.Matches(message, @"'w:''", RegexOptions.Compiled);
// Go backwards. Useful if you need to replace stuff in the message
foreach (var idx in matches.Cast<Match>().Select(m => m.idx).Reverse()) {
int length = 3;
var potentialPath = message.Substring(idx, length);
var lastGoodPath = potentialPath;
// Eat "'" until we get an invalid path
while (Directory.Exists(potentialPath)) {
lastGoodPath = potentialPath;
while (idx+length < message.Length && message[idx+length] != '''')
length++;
length++; // Include the trailing backslash
if (idx + length >= message.Length)
length = (message.Length - idx) - 1;
potentialPath = message.Substring(idx, length);
}
potentialPath = message.Substring(idx);
// Iterate over the files in directory we found until we get a match
foreach (var file in Directory.EnumerateFiles(lastGoodPath)
.OrderByDescending(s => s.Length)) {
if (!potentialPath.StartsWith(file))
continue;
// 'file' contains a valid file name
break;
}
}
}
我是这样做的。
然而,我不认为把消息反复串成子字符串是个好主意。
static void FindFilenamesInMessage(string message)
{
// Find all the "letter colon backslash", indicating filenames.
var matches = Regex.Matches(message, @"'w:''", RegexOptions.Compiled);
int length = message.Length;
foreach (var index in matches.Cast<Match>().Select(m => m.Index).Reverse())
{
length = length - index;
while (length > 0)
{
var subString = message.Substring(index, length);
if (File.Exists(subString))
{
// subString contains a valid file name
///////////////////////
// Payload goes here
//////////////////////
length = index;
break;
}
length--;
}
}
}