2011-06-29 50 views
3

我有一個文本文件,我打開了,它是在一個類似的格式如下:C# - 讀/複製/替換線在文本

10 SOME TEXT 
    20 T A40 
    B B5, C45, D48 
    30 B E25 
    40 B F17, G18 
    60 T H20, I23, 
    B J6, K7, L8, M9, N10, O11, P12, 
    Q31, R32, S33, T34, U35, V36, 
    W37, X38, Y39 
    100 T Z65 
    360 B A1, B4, C5, D6, E7, F10 
    2000 T SOME TEXT 
    423 TEXT 

有了這個文本,我需要能夠讀取它並相應地替換值。如果一個ReadLine以數字開始(即10,20,30,40,60,100,360,2000,423),我需要檢查它後面是否有T,B或文本。唯一的情況是,我需要改變/重新格式化線條,當它們進來並以不同的方式輸出時。

例子:10是好的,除了我想在每個數字前加零以使它們長4位(即10轉到0010,360轉到0360,2000保持不變)。當讀取字符串「B B5,C45,D48」(這是文本中的第三行)時,我需要將它改爲「20A B5,C45,D48」。我需要抓住「B」上方的數字並將其連接到「B」,並用「A」替換「B」。如果不是「B」而是「T」,我只需要刪除「T」。另外,如果一行不是以數字或「B」開頭(即Q31或W37),我需要將該行連接到前一行。


所以後的變化發生就應該是這樣的:

0010 SOME TEXT 
    0020 A40 
    0020A B5, C45, D48 
    0030A E25 
    0040A F17, G18 
    0060 H20, I23, 
    0060A J6, K7, L8, M9, N10, O11, P12, Q31, R32, S33, T34, U35, V36, W37, X38, Y39 
    0100 Z65 
    0360A A1, B4, C5, D6, E7, F10 
    2000 SOME TEXT 
    0423 TEXT 

目前我正在試圖使用正則表達式來做到這一點,但我被告知,有是一個更簡單的方法來做到這一點,我不知道如何。到目前爲止,我已經能夠在數字前添加零。另外,我的代碼在所有內容的末尾添加了「A」,並將原始數字保留在下一行,並且我不抓取以數字開頭的行。

這是我的電流輸出轉向了模樣:

0010A 
    0010 
    0020A 
    0020 

    0030A 
    0030 
    0060A 
    0060 



    0100A 
    0100 
    0360A 
    0360 
    2000 
    2000 
    0423A 
    0423 

我使用正則表達式明明做錯了什麼。

這裏是我當前的代碼:

private void openRefsButton_Click(object sender, EventArgs e) 
    { 
     // Initialize the OpenFileDialog to specify the .txt extension as well as 
     // its intial directory for the file. 
     openRefs.DefaultExt = "*.txt"; 
     openRefs.Filter = ".txt Files|*.txt"; 
     openRefs.InitialDirectory = "C:\\"; 
     openRefs.RestoreDirectory = true; 

     try 
     { 
      // Open the contents of the file into the originalTextRichTextBox. 
      if (openRefs.ShowDialog() == DialogResult.OK && openRefs.FileName.Length > 0) 
       refsTextRichTextBox.LoadFile(openRefs.FileName, RichTextBoxStreamType.PlainText); 

      // Throws a FileNotFoundException otherwise. 
      else 
       throw new FileNotFoundException(); 

      StreamReader refsInput = File.OpenText(openRefs.FileName); 

      string regExpression = @"^[\d]+"; 
      string findNewBottomRegex = @"^B\s"; 

      StringBuilder buildNumberText = new StringBuilder(); 
      StringBuilder formatMatchText = new StringBuilder(); 

      foreach (string allLines in File.ReadAllLines(openRefs.FileName)) 
      { 
       Match newBottomMatch = Regex.Match(allLines, findNewBottomRegex); 
       Match numberStartMatch = Regex.Match(allLines, regExpression); 
       int counter = 0; 

       if (counter < numberStartMatch.Length) 
       { 
        if (numberStartMatch.Value.Length == 2) 
        { 
         if (refsTextRichTextBox.Text.Contains(newBottomMatch.ToString())) 
         { 
          finalTextRichTextBox.AppendText("00" + numberStartMatch + "A\n"); 
         } 

         finalTextRichTextBox.AppendText("00" + numberStartMatch + "\n"); 
        } 

        else if (numberStartMatch.Value.Length == 3) 
        { 
         if (refsTextRichTextBox.Text.Contains(newBottomMatch.ToString())) 
         { 
          finalTextRichTextBox.AppendText("0" + numberStartMatch + "A\n"); 
         } 

         finalTextRichTextBox.AppendText("0" + numberStartMatch + "\n"); 
        } 

        else 
        { 
         if (refsTextRichTextBox.Text.Contains(newBottomMatch.ToString())) 
         { 
          finalTextRichTextBox.AppendText(numberStartMatch + "A\n"); 
         } 

         finalTextRichTextBox.AppendText(numberStartMatch + "\n"); 
        } 
        counter++; 
       } 
      } 
     } 

     // Catches an exception if the file was not opened. 
     catch (Exception) 
     { 
      MessageBox.Show("There was not a specified file path.", "Path Not Found Error", 
          MessageBoxButtons.OK, MessageBoxIcon.Warning); 
     } 
    } 
} 

}

問題(S):

  • 什麼是更好的方式去完成這個任務?
  • 有沒有更改我的代碼更有效和更清潔的建議?
  • 如何正確地將每一行分成數字,T/B,A40每行不一樣?
  • 行正確分割後,如果當前行以「B」開頭,我該如何更換複製行?
    • 如果行以「Q31」或類似行開頭,我該如何將當前行添加到前一行的結尾?
  • 一旦發生這種情況,有沒有辦法將所有東西連接起來以創建上面的speficied格式?

工作流程@jaywayco

  • 打開文本文件
  • 讀取文件一行一行
    • 保存在一個字符串列表,每行
  • 拆分每個字符串通過'
  • 找到每個以數字
    • 啓動線替換位,使其4位長度
    • 檢查下面的文本的數字後,看它是否是一個「B」,「T 」,或 「一些TEXT」
      • 如果 「B」 複製上述
        • 行添加的 「A」 到手指的端部
      • 如果 「T」 刪除 「T」
      • 如果「SOME TEXT」無可奈何
  • 查找每個帶有「B」
    • 複製開始行上述線和CONCAT至「B」 前面的數字
      • 按照步驟4.bi
  • 查找每一個開頭線(或SIM卡ILAR到) 「Q31」
    • 的毗連這條線到上線
  • 結束...?
+2

看起來有些政府定義的標準文件格式。 YUCK。 –

回答

2

這裏是一個非常蹩腳的,程序性的解決方案:

using System.IO; 
using System.Collections.Generic; 

namespace ConsoleApplication 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var list = new List<string>(); 

      using (var reader = File.OpenText(@"c:\input.txt")) 
      { 
       while (true) 
       { 
        var line = reader.ReadLine(); 
        if (string.IsNullOrEmpty(line)) break; 
        list.Add(line); 
       } 
      } 

      list = HandleRemoveTRequirement(list); 
      list = HandleFourDigitRequirement(list); 
      list = HandleConcatRequirement(list); 
      list = HandleStartsWithBRequirement(list); 
      list = HandleSecondElementIsBRequirement(list); 

      using (var output = new StreamWriter(@"c:\output.txt")) 
      { 
       foreach (var line in list) 
       { 
        output.WriteLine(line); 
       } 
      } 
     } 

     static List<string> HandleSecondElementIsBRequirement(List<string> list) 
     { 
      var result = new List<string>(); 

      foreach (var line in list) 
      { 
       var parts = line.Split(' '); 

       if (parts[1].Equals("B")) 
       { 
        parts[0] += "A"; 
        parts[1] = string.Empty; 
        result.Add(string.Join(" ", parts).Replace(" ", " ")); 
       } 
       else 
       { 
        result.Add(line); 
       } 
      } 

      return result; 
     } 

     static List<string> HandleStartsWithBRequirement(List<string> list) 
     { 
      var result = new List<string>(); 
      var i = 0; 

      foreach (var line in list) 
      { 
       var parts = line.Split(' '); 

       if (parts[0].Equals("B")) 
       { 
        parts[0] = string.Empty; 
        result.Add(list[i - 1].Split(' ')[0] + "A" + string.Join(" ", parts)); 
       } 
       else 
       { 
        result.Add(line); 
       } 

       i++; 
      } 

      return result; 
     } 

     static List<string> HandleConcatRequirement(List<string> list) 
     { 
      var result = new List<string>(); 

      foreach (var line in list) 
      { 
       var parts = line.Split(' '); 
       int test; 
       if (int.TryParse(parts[0], out test) || parts[0].Equals("B")) 
       { 
        result.Add(line); 
       } 
       else 
       { 
        result[result.Count -1] += line; 
       } 
      } 

      return result; 
     } 

     static List<string> HandleRemoveTRequirement(List<string> list) 
     { 
      var result = new List<string>(); 

      foreach (var line in list) 
      { 
       var parts = line.Split(' '); 
       if (parts[1].Equals("T")) 
       { 
        parts[1] = string.Empty; 
       } 
       result.Add(string.Join(" ", parts).Replace(" ", " ")); 
      } 

      return result; 
     } 

     static List<string> HandleFourDigitRequirement(List<string> list) 
     { 
      var result = new List<string>(); 

      foreach (var line in list) 
      { 
       var parts = line.Split(' '); 
       int test; 
       if (int.TryParse(parts[0], out test)) 
       { 
        parts[0] = parts[0].PadLeft(4, '0'); 
        result.Add(string.Join(" ", parts)); 
       } 
       else 
       { 
        result.Add(line); 
       } 
      } 

      return result; 
     } 
    } 
} 
+0

感謝這幫助我們編寫了一些代碼! – theNoobGuy

1

這些都是很複雜的要求,我會很想實現這個作爲工作流。這樣你可以分離出每個邏輯步驟,這將增加可維護性。

我會被誘惑表示文本文件作爲串數組的數組或甚至一個數據表。然後,你可以寫一個級聯一般功能/變換特定值

+0

我編輯了上面的文本以包含文本工作流程。但是,我覺得我錯過了一些東西。 – theNoobGuy

+0

看起來很好,我認爲所有剩下的工作就是將所有數據「粘合」在一起。爲此,我可能會使用StringBuilder,因爲它具有較少的內存影響,只是簡單的字符串連接。如果你想變得聰明並且走下數據表的路線,你可以將結果轉換爲XML並使用XSLT生成輸出 – jaywayco

1

一種方法可能接近這個類同jaywayco的。

我會用將每行分裂用空格到它自己的數組開始。將該數組放入數組數組中。從那裏你可以考慮你的工作流程。你的行數組被空格分開,你可以根據第一個值確定如何打印它,如數字或字母B等等......如果它是B,你就知道它應該以數組[i-1]開頭,第一個值,這將是數等,您不得不考慮通過邏輯有點,但我認爲你能理解我來自哪裏。我不知道這是否是最好的方法還是不行,但我認爲這是我會解決它的辦法。祝你好運!

編輯:下面是一些模擬代碼...

var mainArray = new Array[textFile.Count]; 
//obviously get the count of number of lines set that to the size of your array object. 

for(int i=0; i < mainArray.Length; i++) 
{ 
    var line = methodToGetLineFromTextFile[i]; 
    string[] lineArray = line.Split(' '); 
    mainArray[i] = lineArray; 
} 

//Once you have everything loaded into your arrays, apply your workflow logic. 

希望這有助於!

+0

謝謝,這有幫助!我很感激。 :) – theNoobGuy

1

我想要完成這項任務的方法是根據您的要求編寫一組單元測試,然後讓它們一次通過一個(每個需求有一個測試)。

正如jaywayco建議的那樣,我會將文件讀入一行數組,然後將您的每條規則實現爲可以單獨測試的行轉換方法。我可能會分離出可以選擇應用哪種轉換的方法。然後遍歷線並應用轉換。

+0

謝謝Alex Peck,我會這麼做! – theNoobGuy