在字符串中查找无界文件路径

时间:2013-04-17 15:53:25

标签: c# parsing

我有一个闭源第三方软件生成的这些错误消息,我需要从中提取文件路径。

所述文件路径为:

  • 没有界限(即没有被引号,括号,括号等包围)
  • rooted(即以<letter>:\开头,例如C:\
  • 不保证有文件扩展名
  • 表示保证在运行提取代码的计算机上存在的文件(仅文件,而不是目录)。
  • 由任何有效字符组成,包括空格,使其难以发现(例如C:\This\is a\path \but what is an existing file path here

需要注意的是,每条消息可以有0个或更多文件路径。

如何在错误消息中找到这些文件路径?

我在下面提出了一个答案,但我觉得有一个更好的方法来解决这个问题。

2 个答案:

答案 0 :(得分:3)

对于每场比赛,请期待下一个'\'字符。所以你可能得到“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;
        }
    }
}

答案 1 :(得分:1)

我就是这样做的。

我不认为一遍又一遍地对消息进行细分是一个好主意。

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--;
        }
    }
}