2017-05-18 27 views
2

提取數據我從OkHttpClient類似這樣的回覆:快速的方法來從字符串

{"CUSTOMER_ID":"928941293291"} 
{"CUSTOMER_ID":"291389218398"} 
{"CUSTOMER_ID":"1C4DC4FC-02Q9-4130-S12B-762D97FS43C"} 
{"CUSTOMER_ID":"219382198"} 
{"CUSTOMER_ID":"282828"} 
{"CUSTOMER_ID":"21268239813"} 
{"CUSTOMER_ID":"1114445184"} 
{"CUSTOMER_ID":"2222222222"} 
{"CUSTOMER_ID":"99218492183921"} 

我想提取所有的客戶ID是Long類型的(然後跳到1C4DC4FC-02Q9-4130-S12B-762D97FS43C)在minId和maxId之間。 這是我實現:

final List<String> customerIds = Arrays.asList(response.body().string() 
        .replace("CUSTOMER_ID", "") 
        .replace("\"", "") 
        .replace("{", "").replace(":", "") 
        .replace("}", ",").split("\\s*,\\s*")); 
for (final String id : customerIds) { 
    try { 
     final Long idParsed = Long.valueOf(id); 
     if (idParsed > minId && idParsed < maxId) { 
      ids.add(idParsed); 
     } 
    } catch (final NumberFormatException e) { 
     logger.debug("NumberFormatException", e); 
    } 
} 

我有客戶ID(約1M)的一個長長的清單,然後性能是非常重要的。這是我的行爲的最佳實施?

+1

是不知何故json,你可以解析?? –

+1

我想我在那裏看到UUID,做min和max甚至在這裏有意義嗎? –

+0

@ΦXocę웃Пepeúpaツ我的例子中報等於我的使用情況(僅針對multipled 1M行) –

回答

1

既然你有一個大文件,那麼逐行閱讀內容是一種可行的方式,並且不要替換CUSTOMER_ID,而是定義一個更好的正則表達式模式。

按照你的方法:更換USER_ID和使用正則表達式:

String x = "{\"CUSTOMER_ID\":\"928941293291\"}{\"CUSTOMER_ID\":\"291389218398\"}{\"CUSTOMER_ID\":\"1C4DC4FC-02Q9-4130-S12B-762D97FS43C\"}" 
      + "{\"CUSTOMER_ID\":\"99218492183921\"}"; 

x = x.replaceAll("\"CUSTOMER_ID\"", ""); 
Pattern p = Pattern.compile("\"([^\"]*)\""); 
Matcher m = p.matcher(x); 
while (m.find()) { 
    System.out.println(m.group(1)); 
} 

或實現匹配所有之間正則表達式: 「」}

String x = "{\"CUSTOMER_ID\":\"928941293291\"}{\"CUSTOMER_ID\":\"291389218398\"}{\"CUSTOMER_ID\":\"1C4DC4FC-02Q9-4130-S12B-762D97FS43C\"}" 
      + "{\"CUSTOMER_ID\":\"99218492183921\"}"; 

Pattern p = Pattern.compile(":\"([^\"]*)\"}"); 
Matcher m = p.matcher(x); 
while (m.find()) { 
    System.out.println(m.group(1)); 
} 

所以無需更換CUSTOMER_ID

+0

對於1點M的記錄使用正則表達式來打!?你需要64GB的RAM或類似的東西 –

+0

喔!!我搞砸通過線的那部分 –

+0

然後讀線可以是一個辦法 –

0

可以忽略所有非數值型字段

long[] ids = 
    Stream.of(response.body().string().split("\"")) 
      .mapToLong(s -> parseLong(s)) 
      .filter(l -> l > minId && i < maxId) 
      .toArray(); 

static long parseLong(String s) { 
    try { 
     if (!s.isEmpty() && Character.isDigit(s.charAt(0))) 
      return Long.parseLong(s); 
    } catch (NumberFormatException expected) { 
    } 
    return Long.MIN_VALUE 
} 

或者,如果你使用的是Java 7

List<Long> ids = new ArrayList<>(); 
for (String s : response.body().string().split("\"")) { 
    long id = parseLong(s); 
    if (id > minId && id < maxId) 
     ids.add(id); 
} 
+0

不使用Java 8 –

+1

@LuigiSaggese加入如何7. –

0

您可以使用Files.lines()從您的文件流數據。在這裏,我演示了從List使用stream

List<String> sample = Arrays.asList(
     "{\"CUSTOMER_ID\":\"928941293291\"}", 
     "{\"CUSTOMER_ID\":\"291389218398\"}", 
     "{\"CUSTOMER_ID\":\"1C4DC4FC-02Q9-4130-S12B-762D97FS43C\"}", 
     "{\"CUSTOMER_ID\":\"219382198\"}", 
     "{\"CUSTOMER_ID\":\"282828\"}", 
     "{\"CUSTOMER_ID\":\"21268239813\"}", 
     "{\"CUSTOMER_ID\":\"1114445184\"}", 
     "{\"CUSTOMER_ID\":\"2222222222\"}", 
     "{\"CUSTOMER_ID\":\"99218492183921\"}" 
); 

static final long MIN_ID = 1000000L; 
static final long MAX_ID = 1000000000000000000L; 

public void test() { 
    sample.stream() 
      // Extract CustomerID 
      .map(s -> s.substring("{\"CUSTOMER_ID\":\"".length(), s.length() - 2)) 
      // Remove any bad ones - such as UUID. 
      .filter(s -> s.matches("[0-9]+")) 
      // Convert to long - assumes no number too big, add a further filter for that. 
      .map(s -> Long.valueOf(s)) 
      // Apply limits. 
      .filter(l -> MIN_ID <= l && l <= MAX_ID) 
      // For now - just print them. 
      .forEach(s -> System.out.println(s)); 
} 
+0

我的應用程序不能使用Java 8做同樣在Java中我的應用程序 –

1

儘量避免例外!當10%-20%的數字解析失敗時,它需要10倍的時間來執行,並且它(你可以爲它編寫一個litte測試)。

如果輸入酷似你顯示它,你應該使用廉價的操作: 通過線與BufferedReader線讀取文件(就像前面提到過)或者(如果你有整個數據串)我們StringTokenizer處理每行分隔。 每行以{"CUSTOMER_ID":"開頭,以"}結尾。不要使用replace或正則表達式(更糟糕的是)刪除它!只需使用一個簡單的substring

String input = line.substring(16, line.length() - 2) 

爲避免你需要找到度量ID和UUID(區分異常?),所以你的解析工作無一例外。例如,您的ID將是正位,但您的UUID包含減號,或者long只能包含20位數字,但您的UUID包含35個字符。所以這是一個簡單的if-else而不是try-catch。

對於那些認爲在解析數字時不能捕獲NumberFormatException的人:如果存在無法解析的id,則整個文件已損壞,這意味着您不應該嘗試繼續,但會失敗。


這是一個小測試,看看捕獲異常和測試輸入之間的性能差異:

long REPEATS = 1_000_000, startTime; 
final String[] inputs = new String[]{"0", "1", "42", "84", "168", "336", "672", "a-b", "1-2"}; 
for (int r = 0; r < 1000; r++) { 
    startTime = System.currentTimeMillis(); 
    for (int i = 0; i < REPEATS; i++) { 
     try { 
      Integer.parseInt(inputs[i % inputs.length]); 
     } catch (NumberFormatException e) { /* ignore */ } 
    } 
    System.out.println("Try: " + (System.currentTimeMillis() - startTime) + " ms"); 
    startTime = System.currentTimeMillis(); 
    for (int i = 0; i < REPEATS; i++) { 
     final String input = inputs[i % inputs.length]; 
     if (input.indexOf('-') == -1) 
      Integer.parseInt(inputs[i % inputs.length]); 
    } 
    System.out.println("If: " + (System.currentTimeMillis() - startTime) + " ms"); 
} 

我的結果是:

  • 〜20毫秒(測試)和〜200毫秒(捕捉)有20%無效輸入。
  • 〜22毫秒(測試)和〜130毫秒(捕捉)與10%無效輸入。

由於JIT或其他優化,這些類型的性能測試很容易完成。但我認爲你可以看到一個方向。

+0

你認爲有更好的表現,以檢查是否字符串包含特殊字符(例如「 - 」 )比拋出NumberFormatException跳過無效的長? –

+0

是的!但這取決於你的輸入。在這裏,你期望無效的數字,你想濫用try-catch控制流。我對我的答案附了一個小測試。 – Obenland

+0

感謝您的澄清:) –

0

首先,你應該嘗試逐行讀取文件中的行。然後從每行你應該提取id如果它匹配的模式,並收集到一個數組。這裏是用python實現的類似解決方案。

import re 
# Open the file 
with open('cids.json') as f: 
    # Read line by line 
    for line in f: 
     try: 
      # Try to extract matching id with regex pattern 
      _id = re.search('^{[\w\W]+:"([A-Z\d]+-[A-Z\d]+-[A-Z\d]+-[A-Z\d]+-[A-Z\d]+)"}', line).group(1) 
      customer_ids.append(_id) 
     except: 
      print('No match')