使用Java创建一个正则表达式来解析文件

4
我有一个日志文件,其格式如下所示:
225:org.powertac.common.Competition::0::new::game-0
287:org.powertac.common.Competition::0::withSimulationBaseTime::1255132800000
288:org.powertac.common.Competition::0::withTimezoneOffset::-6
288:org.powertac.common.Competition::0::withLatitude::45
289:org.powertac.common.Competition::0::withBootstrapTimeslotCount::336
289:org.powertac.common.Competition::0::withBootstrapDiscardedTimeslots::24
290:org.powertac.common.Competition::0::withMinimumTimeslotCount::1400
290:org.powertac.common.Competition::0::withExpectedTimeslotCount::1440
291:org.powertac.common.Competition::0::withTimeslotLength::60
291:org.powertac.common.Competition::0::withSimulationRate::720
292:org.powertac.common.Competition::0::withTimeslotsOpen::24
292:org.powertac.common.Competition::0::withDeactivateTimeslotsAhead::1
300:org.powertac.du.DefaultBrokerService$LocalBroker::1::new::default broker
300:org.powertac.du.DefaultBrokerService$LocalBroker::1::setLocal::true
2074:org.powertac.common.RandomSeed::2::init::CompetitionControlService::0::game-setup::5354386935242895562
2157:org.powertac.common.TimeService::null::setCurrentTime::2009-10-10T00:00:00.000Z
2197:org.powertac.common.RandomSeed::3::init::AccountingService::0::interest::-8975848432442556652
2206:org.powertac.common.RandomSeed::4::init::TariffMarket::0::fees::-6239716112490883981
2213:org.powertac.common.msg.BrokerAccept::null::new::1
2214:org.powertac.common.msg.BrokerAccept::null::new::1::null
2216:org.powertac.common.RandomSeed::5::init::org.powertac.du.DefaultBrokerService::0::pricing::8741252857248937781
2226:org.powertac.common.TariffSpecification::6::new::1::CONSUMPTION
2231:org.powertac.common.Rate::7::new
2231:org.powertac.common.Rate::7::withValue::-0.5
2232:org.powertac.common.Rate::7::setTariffId::6

模式如下: 对于一个新对象:

<id>:<classname>::<order_of_execution>::<new>::<args>

对于一个方法调用:

 <id>:<classname>::<order_of_execution>::<method_name>::<args>

对于一个内部类:

 <id>:<classname$innerclass>::<order_of_execution>::<method_name or new>::<args>

对于一个 init 调用:
 <id>:<classname>::<order_of_execution>::<init>::<args>

我需要一个正则表达式来处理所有情况,并且能够像示例中所示检索每个值。 如果我想创建一个新对象,那么我会使用Java中的Reflection API。 例如:
2231:org.powertac.common.Rate::7::new

将被解析为"2231", "org.powertac.common.Rate", "7", "new",args = {}。 我该如何想出这样的正则表达式?

3个回答

2

使用带有捕获组的Matcher

String s = "225:org.powertac.common.Competition::0::new::game-0";
Pattern p = Pattern.compile("([^:]+):([^:]+)::([\\d]+)::([^:]+)::(.+)");
Matcher m = p.matcher(s);
if (m.find()) {
  String id = m.group(1);
  String className = m.group(2);
  int orderOfExecution = Integer.valueOf(m.group(3));
  String methodNameOrNew = m.group(4);
  String[] arguments = m.group(5).split("::");
}

或者更简单的方式,使用将分隔符设置为::?java.util.Scanner
Scanner scanner = new Scanner(s);
scanner.useDelimiter("::?");
int id = scanner.nextInt();
String className = scanner.next();
int orderOfExecution = scanner.nextInt();
String methodNameOrNew = scanner.next();
scanner.useDelimiter("$").skip("::");
String[] arguments = scanner.next().split("::");

Joao,你的正则表达式能处理所有情况吗? - cybertextron
@philippe:是的,它们都遵循相同的模式。你只需要解释一下,例如,如果第4组是“new”,那么它就是一个新对象,否则,它就是一个方法。我已经添加了一种更简单的方法,使用Scanner代替。 - João Silva

1
不要试图将所有内容都塞进一个正则表达式中。为每个模式创建一个正则表达式,并对每一行进行匹配,直到找到匹配的模式为止。然后您可以相应地解析。
伪代码:
for line in file:
    if re.match(patNew, line):
        parseNew(line)
    elif re.match(patMethod, line):
        parseMethod(line)
    ...

一个用于匹配 <id>:<classname>::<order_of_execution>::<new>::<args> 的正则表达式看起来应该是这样的:
([0-9]+):(.*?)::([0-9]+)::(new)(?:::(.*))?

我可以确定每个情况,但是我该如何为这种情况创建一个正则表达式,例如:<id>:<classname> :: <order_of_execution> :: <new> :: <args>。 - cybertextron
@philippe 我已经修复了正则表达式的一个小问题。在 regextester.com 上测试并且可以工作。 - Lanaru

-1
由于值是以冒号分隔的,且不能包含冒号本身,因此无需转义或引用,所以您只需要一个简单的。
(.*):(.*)::(.*)::(.*)::(.*)

如果参数是可选的,请使用
(.*):(.*)::(.*)::([^:]*)(?:::(.*))?

这些值分别在1到5组中。例如,要确定日志条目是否为构造函数调用,请检查第4组是否等于“new”。


你能提供更多细节吗?我喜欢你的方法。 - cybertextron
1
以下冒号将防止第一个 .* 匹配任何内容。这个正则表达式很好用,你可以自己测试一下。 - Cephalopod
巧妙的技巧,删除错误的评论,使其看起来像是我对另一个问题回答了无意义的话,并且同时不取消点踩的赞成;-) - Cephalopod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接