2013-04-17 34 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--; 
     } 
    } 
}