2010-09-21 57 views
0

對於我的數據結構項目,目標是閱讀提供的文件,其中包含超過10000首帶有明確標記的藝術家,標題和歌詞的歌曲,並且每首歌曲用一行雙引號分隔。我寫這個代碼來解析文本文件,它的工作原理,用了不到3秒
運行時間 閱讀422K行文字
的創建宋對象
加說宋到一個ArrayList
該代碼還可以針對防禦性編程進行優化嗎?

我寫的解析代碼是:

if (songSource.canRead()) { //checks to see if file is valid to read 
    readIn= new Scanner(songSource); 
    while (readIn.hasNextLine()) { 
do { 
    readToken= readIn.nextLine(); 

      if (readToken.startsWith("ARTIST=\"")) { 
    artist= readToken.split("\"")[1]; 
     } 
     if (readToken.startsWith("TITLE=\"")) { 
    title= readToken.split("\"")[1]; 
     } 
     if (readToken.startsWith("LYRICS=\"")) { 
    lyrics= readToken.split("\"")[1]; 
     } else { 
    lyrics+= "\n"+readToken; 
     }//end individual song if block 
} while (!readToken.startsWith("\"")); //end inner while loop 

    songList.add(new Song(artist, title, lyrics)); 

    }//end while not EOF 
} //end if file can be read 

我和我的介紹到算法教授關於這個項目的代碼說話,他說,我應該嘗試更多的防守在我的代碼允許其他人提供的數據不一致。最初我在Artist,Title和Lyrics字段之間使用了if/else塊,並且在他的建議中,我將其改爲順序if語句。雖然我可以看到他的觀點,但是使用這個代碼示例,我怎樣才能更加防禦地考慮輸入不一致?

+0

這是一個讓你的代碼「更好」的開放性問題。考慮讓它成爲一個社區Wiki? – pascal 2010-09-21 02:17:23

回答

2

你假設輸入是完美的。如果你順便看看你的應用是目前的設置,根據您的算法的快速讀取的數據是這樣的

ARTIST="John" 
TITLE="HELLO WORLD" 
LYRICS="Sing Song All night long" 
" 

但考慮到情況

ARTIST="John" 
TITLE="HELLO WORLD" 
LYRICS="Sing Song All night long" 
" 
ARTIST="Peter" 
LYRICS="Sing Song All night long" 
" 

根據你的算法,你現在有2首歌曲定性爲

songList = { Song("JOHN", "HELLO WORLD", "Sing Song All night long"), 
      Song("Peter", "HELLO WORLD", "Sing Song All night long") } 

在當前的算法,藝術家和標題暴露,並會在即使它們沒有定義的第二首歌曲出現。你需要重置你的三個變量。

在你的其他地方,你只是將完整的一行寫入歌詞。如果你已經把Lyrics拉出來了,你現在壓倒一切。測試用例

ARTIST="John" 
LYRICS="Sing Song All night long" 
TILET="HELLO WORLD" 
" 

考慮將此記錄發送到錯誤狀態。所以當批量讀取完成後,可以生成並修復錯誤報告。

你也只是在藝術家被讀入後才考慮EOF。如果EOF發生在藝術家閱讀過程中,並且文件沒有以「。」結尾,你會在那裏得到一個異常。另一個支票hasNextLine()

+0

我選擇了你的回答作爲答案,因爲即使我沒有在當前項目中使用它,你已經給了我一個具體的例子來解決用戶輸入錯誤而不會導致程序崩潰。 – Jason 2010-10-14 10:46:41

4

我將取代如:

artist= readToken.split("\"")[1]; 

String[] parts = readToken.split("\""); 
if(parts.length >= 2) artist = parts[1]; 
else continue; 

其他修改將包括:

  1. 重置本地變量(所以你不小心拿錯藝術家對於一首歌曲,如果在第一首後沒有提供某首歌曲的歌手)
  2. 決定如果某些數據丟失怎麼辦 - 您是否仍想將歌曲添加到歌曲列表中?
+0

正則表達式可以進行優化還是針對每次迭代構建? – 2010-09-21 01:56:36

+0

@Thorborn--不會影響代碼的健壯性......只有它的性能。即使如此,也不是很多。 (IIRC,Pattern.compile方法使用簡單的一個正則表達式緩存來避免重複編譯相同的正則表達式,在這種情況下,它會有效)。 – 2010-09-21 02:04:20

+0

感謝這個例子,你給了我一些想法。 – Jason 2010-09-21 02:13:56

2

在現實世界中,對數據完整性有一些保證。在處理用戶輸入(無論是來自stdin還是文件)的情況下,有一些項目定義的範例用於通知用戶需要注意的問題。例如,當編譯器編譯代碼或執行腳本的shell遇到不一致時,它可能會暫停並在其下面的第二行打印出包含不一致的行,該行使用「^」符號表示問題。

所以這裏有一個基本的問題要問自己:
1.是否每條線都保證包含每個字段?
2.是否保證了字段的排序?

如果這些是輸入合同的條件並被違反,您應該忽略/報告該行。如果他們不是輸入的條件,那麼你需要處理它..你目前沒有。

+0

這種事情正是我喜歡這個網站的原因。我想我遇到了這個CS程序設計方式的一些缺點。它似乎更感興趣的是首先獲得整體概念,然後再詳述,但除了關於代碼語法和空白的講義以外,很少強調像防禦性編碼這樣的適當程序。 – Jason 2010-09-21 02:17:41

0

這裏有一些問題是可以解決:

  • 你的代碼假定有之前(例如)「藝術家」,沒有圍繞「=」號等沒有空格。

  • 您的代碼假定關鍵字全部大寫。有人可以使用小寫或混合大小寫。

  • 你的代碼假設一條不以keyword=\"開頭的行是歌曲歌詞的延續。但是如果用戶輸入了ARTOST="Sting"呢?或者,如果用戶試圖使用兩行藝術家姓名?

最後,我不相信,在更換「如果別人」,「如果」,在這種情況下作出了代碼的健壯性任何區別。

1

我看到一些在這裏失蹤的東西傑森。

我認爲if/else很好,它不會改變邏輯。但是,您應該儘可能限制變量的範圍。通過在while循環中聲明藝術家,標題等,它們將被初始化爲空(或其他),所以如果一個條目缺少藝術家,那麼它將不會獲得最後一個條目的值。

此外,如果標題,藝術家等在其中有引用,會發生什麼?這是如何處理的?怎麼樣似乎是多行的歌詞對嗎?

如果存在未知字段會發生什麼情況 - 可能是拼寫錯誤?它將被添加到歌詞的結尾,這看起來不正確。只有在找到LYRICS字段後,才能追加。如果歌詞爲空,則它將以「空」開始。

0

處理異常(我猜的掃描儀可以拋出InputMismatchException爲無效字符)。

它看起來像do { } while (...)可以無限循環,如果形成不良的文件,並結束文件已到達

沒有阻止artisttitle不能爲空。