我的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"}
我想在minId和maxId之间提取所有类型为long的customerId(然后跳过1C4DC4FC-02Q9-4130-S12B-762D97FS43C)。 这是我的实施:
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);
}
}
我有一长串customerId(大约1M),那么性能非常重要。这是我行为的最佳实现吗?
答案 0 :(得分: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
答案 1 :(得分:1)
我会使用BufferedReader逐行读取字符串 https://www.mkyong.com/java/how-to-read-file-from-java-bufferedreader-example/
每行我会减少替换量
String id= line.replace({"CUSTOMER_ID":", "");
id = id.substring(0, id.length-2); //to avoid one more replace
然后应用尝试解析长逻辑,将成功尝试添加到列表中。
答案 2 :(得分:1)
尽量避免异常!当10%-20%的数字解析失败时,它需要多10倍的时间来执行它(你可以为它编写一个litte测试)。
如果您的输入与您展示的完全相同,则应使用便宜的操作:
使用BufferedReader
逐行读取文件(如前所述)或(如果您将整个数据作为字符串)我们StringTokenizer
来处理每行分隔。
每行以{"CUSTOMER_ID":"
开头,以"}
结尾。不要使用replace
或正则表达式(更糟糕的是)删除它!只需使用一个简单的substring
:
String input = line.substring(16, line.length() - 2)
为避免异常,您需要找到用于区分id和UUID(?)的度量标准,以便您的解析无异常。例如,您的ID将是positiv,但您的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");
}
我的结果是:
由于JIT或其他优化,这些类型的性能测试很容易做到。但我认为你可以看到一个方向。
答案 3 :(得分: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);
}
答案 4 :(得分:0)
您可以使用Files.lines()来传输文件中的数据。在这里,我演示了使用stream
中的List
。
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));
}
答案 5 :(得分: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')