2014-03-13 40 views
1

我有數據從腳本來,其通常是這樣的線(單線示例):解析一行數據:分裂VS正則表達式

1234567890;group1;varname1;133333337;prop1=val1;prop2=val2;prop3=val3 

我需要打破各行成關鍵值的項目對於Map來說,每個項目由分隔符字符串分隔(示例中的;,但它也可以是自定義的)。前4個項目是靜態的,這意味着只有值在行中,並且鍵已知。其餘的是鍵值項目的可變數量(0或更多key=value塊)。 請首先看看下面的輸出給你一個想法。

我已經有兩種工作方法來完成這項工作,其中兩者都爲同一行拋出相同的輸出。出於好奇,我設立了一個測試課來演示這兩種方法以及一些(簡單的)性能分析。 請注意無效的輸入處理在下面顯示的方法中是最小的。 (使用Apache共享)

字符串分割:

private static List<String> splitParsing(String dataLine, String separator) { 
    List<String> output = new ArrayList<String>(); 
    long begin = System.nanoTime(); 

    String[] data = StringUtils.split(dataLine, separator); 

    if (data.length >= STATIC_PROPERTIES.length) { 
     // Static properties (always there). 
     for (int i = 0; i < STATIC_PROPERTIES.length; i++) { 
      output.add(STATIC_PROPERTIES[i] + " = " + data[i]); 
     } 

     // Dynamic properties (0 or more). 
     for (int i = STATIC_PROPERTIES.length; i < data.length; i++) { 
      String[] fragments = StringUtils.split(data[i], KEYVALUE_SEPARATOR); 
      if (fragments.length == 2) { 
       output.add(fragments[0] + " = " + fragments[1]); 
      } 
     } 
    } 

    long end = System.nanoTime(); 
    output.add("Execution time: " + (end - begin) + "ns"); 
    return output; 
} 

正則表達式(使用JDK 1.6):

private static List<String> regexParsing(String dataLine, String separator) { 
    List<String> output = new ArrayList<String>(); 
    long begin = System.nanoTime(); 

    Pattern linePattern = Pattern.compile(StringUtils.replace(DATA_PATTERN_TEMPLATE, SEP, separator)); 
    Pattern propertiesPattern = Pattern.compile(StringUtils.replace(PROPERTIES_PATTERN_TEMPLATE, SEP, separator)); 

    Matcher lineMatcher = linePattern.matcher(dataLine); 
    if (lineMatcher.matches()) { 
     // Static properties (always there). 
     for (int i = 0; i < STATIC_PROPERTIES.length; i++) { 
      output.add(STATIC_PROPERTIES[i] + " = " + lineMatcher.group(i + 1)); 
     } 

     Matcher propertiesMatcher = propertiesPattern.matcher(lineMatcher.group(STATIC_PROPERTIES.length + 1)); 
     while (propertiesMatcher.find()) { 
      output.add(propertiesMatcher.group(1) + " = " + propertiesMatcher.group(2)); 
     } 
    } 

    long end = System.nanoTime(); 
    output.add("Execution time: " + (end - begin) + "ns"); 
    return output; 
} 

主要方法:

public static void main(String[] args) { 
    String input = "1234567890;group1;varname1;133333337;prop1=val1;prop2=val2;prop3=val3"; 

    System.out.println("Split parsing:"); 
    for (String line : splitParsing(input, ";")) { 
     System.out.println(line); 
    } 

    System.out.println(); 

    System.out.println("Regex parsing:"); 
    for (String line : regexParsing(input, ";")) { 
     System.out.println(line); 
    } 
} 

常量:

// Common constants. 
private static final String TIMESTAMP_KEY = "TMST"; 
private static final String GROUP_KEY = "GROUP"; 
private static final String VARIABLE_KEY = "VARIABLE"; 
private static final String VALUE_KEY = "VALUE"; 
private static final String KEYVALUE_SEPARATOR = "="; 
private static final String[] STATIC_PROPERTIES = { TIMESTAMP_KEY, GROUP_KEY, VARIABLE_KEY, VALUE_KEY }; 

// Regex constants. 
private static final String SEP = "{sep}"; 
private static final String PROPERTIES_PATTERN_TEMPLATE = SEP + "(\\w+)" + KEYVALUE_SEPARATOR + "(\\w+)"; 
private static final String DATA_PATTERN_TEMPLATE = "(\\d+)" + SEP + "(\\w+)" + SEP + "(\\w+)" + SEP + "(\\d+\\.?\\d*)" 
     + "((?:" + PROPERTIES_PATTERN_TEMPLATE + ")*)"; 
從主要的方法

輸出:

Split parsing: 
TMST = 1234567890 
GROUP = group1 
VARIABLE = varname1 
VALUE = 133333337 
prop1 = val1 
prop2 = val2 
prop3 = val3 
Execution time: 8695796ns 

Regex parsing: 
TMST = 1234567890 
GROUP = group1 
VARIABLE = varname1 
VALUE = 133333337 
prop1 = val1 
prop2 = val2 
prop3 = val3 
Execution time: 1250787ns 

從輸出來看(我跑多次),似乎正則表達式的方法是在性能方面更有效,儘管我最初的想法朝着更分裂方法。但是,我不確定這種性能分析的代表性如何。

我的問題是:

  • 這兩個方法將是最好的或更易於使用無效輸入處理? (例如:靜態項目丟失,格式無效等)。
  • 哪種方法不太可能產生意想不到的行爲?
  • 爲什麼正則表達式方法更快?我會假設相反,因爲Matcher s和Pattern必須有一個更復雜的邏輯背後。我的表現分析是否具有代表性?
+1

考慮到'System.out.println'的調用,我會擔心報告的持續時間的有效性。將文本收集到某種字符串生成器並在'end = System.nanoTime();'後面打印可能會更好。 – AdrianHHH

+0

確實!原始上下文中的代碼將解析的項目添加到「List」中,我將使用該行爲調整上面的代碼。 –

+0

@AdrianHHH我用你的建議編輯了這個問題。 –

回答

0

最終,經過測試和擺弄它,我與字符串分割方法去,原因如下:

  • 哪這兩種方法對於無效的輸入處理來說最好還是比較容易處理? (例如:靜態項目丟失,格式無效等)。

以極快的,我可以很容易地找出所分析的字符串的一部分發生故障,並記錄準確和有用的警告信息,其中與正則表達式是方式更難以如願。

  • 哪種方法不太可能產生意外的行爲?

由於解析行的內容不需要驗證或驗證,我發現使用拆分更可靠。隨着正則表達式,我總是以太限制內容或東西太寬鬆結果,給出了意想不到的結果。

使用拆分方法,我簡單地拆分分隔符,打包每個鍵值對,就是這樣。

  • 爲什麼正則表達式的方法更快?我會假設相反,因爲Matcher s和Pattern必須有一個更復雜的邏輯背後。我的表現分析是否具有代表性?

感謝Stye's answer該部分,尤其是有關Split/Match/indexOf實驗的有趣參考。

1

我會盡量解決您的問題:

  • 這兩個方法將是最好的或更易於使用無效輸入處理? (例如:靜態項目丟失,格式無效等)。

相信匹配器的方法,因爲你可以簡單地遍歷您的申報模式的數組,並使用在每個Matcher#usePattern(Pattern P)。我覺得它乾淨清晰,將所有想要的正則表達式放在一個地方,並且快速地爲每個正則表達式運行。

  • 爲什麼正則表達式的方法更快?我認爲相反,因爲匹配者和模式必須有一些更復雜的邏輯。我的表現分析是否具有代表性?

您正在使用Apache Commons實現的split。根據他們的documentation,他們正在使用String Tokenizer的專門實現,如experiment所示,它比String#split(Str regex)(它使用String#indexOf())慢,也比Matcher &模式方法慢。

  • 哪種方法不太可能產生意外的行爲?

通用的問題,但我會用Apache Commons的方法去。它的一個安全優勢是它爲你做空檢查。引用StringUtils類的描述:「對String無效的操作」。 (引自StringUtils文檔,鏈接發佈在第二個問題的答案中)。除此之外,這一切都取決於你:)

+0

分裂實驗問題真的很有趣。不幸的是'indexOf(...)'技術不能在我的代碼中實現(因爲它只有一個字符),但我會對結果感到好奇。 –