2013-04-17 28 views
1

我有这些由需要提取文件路径的封闭源第三方软件生成的错误消息。在字符串中查找无界文件路径

的所述文件路径是:

  • 无界
  • 根(即,不是由引号,圆括号,括号等包围)
  • 不能保证(即,具有<letter>:\C:\开始)有一个文件扩展名
  • 表示在运行提取代码的计算机上保证存在的文件(只有文件,而不是目录)。
  • 由任何有效的字符,包括空格,这使得它们很难被发现(例如C:\This\is a\path \but what is an existing file path here

需要说明的是,可以存在每个消息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; 
     } 
    } 
} 
+0

听起来很明智! :-)今天晚些时候我会试一试,让你知道它的价格。 – joce

+0

确实比较快!在55K消息的运行中,我的解决方案平均约50秒,而您的平均值大概为9秒!请记住,如果我通过实施您的解决方案来编辑​​您的文章? – joce

+0

@Joce:去吧。 –

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