2017-06-21 14 views
0

Guavaスプリッタを使用してログファイルを解析しようとしています。ログファイルは次のようになります。Guavaスプリッタをキー値マップに文字列に含まれるスプリッタ文字で埋め込みます。

appName=XXX clientIp=X.X.X timestamp="2017-06-05T13:22:12-07:00" request="POST /forward HTTP/1.1" statusCode=204 bytesOut=1167 totalTime=0.062 bytesIn=1289 sourceHost=XXXX connId=49936598 connReqs=9 upInstance=XXX:104:XXX-XXX:8664:17F34 upConnectSec=0.052 upAddr="XX.XX.XX:123" upHost="vcv08it-cvcv2801:8464" upHdrTimeSec=0.058 upRespTimeSec=0.058 pid=32561 upStatusCode=204 message="Access Log" corrKey=GMIFCDIKRZR2T4VZQXJA2IT6 upCached=- length=0 partition=XXX location="= /v1/tXXXX" xff="XX.XX.XX.XX" referer="-" user-agent="Apache-HttpAsyncClient/4.1.1 (Java/1.8.0_131)\" rateLimitCurrentValues="--" rateLimitTimeMs=\"-:-" 

私はそれを解析するためにこのコードを使用:

Map<String, String> parserMap; 
parserMap = Splitter.onPattern("\\s(?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)") 
.omitEmptyStrings() 
.withKeyValueSeparator(Splitter.onPattern("=")) 
.split(line); 

私の問題は、文字列内の「=」を持っている場所=「=/V1/TXXXX」フィールドで、 current withKeyValueSeperatorはそれを解析できません。すべてのフィールドを正しく取得するためにパターンを変更する方法を教えてください。

+0

この作業を行うことができれば、私は軽く驚いています。これを処理するのに十分なスマートなカスタムが必要かもしれません。 –

+0

@LouisWasserman、ファンシーなものを使用する必要はありません...正規表現を使って実行できます –

答えて

0

keyValueSeparatorがチャンク内で複数回出現するため、例外java.lang.IllegalArgumentException: Chunk [location="= /v1/tXXXX"] is not a valid entryがコードからスローされます。あなたはkeyValueSeparatorを調整して、等号とそれに続く値パターンが一致するようにすることができます。例えば:あなたのライン内key="key=value"のようなものを持っている場合、これは動作しないこと

final String keyPattern = "\\S+"; 
final String valuePattern = "(\\S+|\"[^\"]*\")"; 
parserMap = Splitter.onPattern("\\s(?=" + keyPattern + "=" + valuePattern + ")") 
     .omitEmptyStrings() 
     .withKeyValueSeparator(Splitter.onPattern("=(?=" + valuePattern + ")")) 
     .split(line); 

は注意してください。

1

ないグアバスプリッタは動作しますが、あなたが定期的にPatternMatcherクラスを使用している場合、あなたはあなたのキーと値をキャプチャするために正規表現の下に使用することができますどのように確認してください。

([\w-]+?)=(".*?"|\S+) 

Regex demo

Javaコード

String text = "your string"; 
Pattern pattern = Pattern.compile("([\\w-]+?)=(\".*?\"|\\S+)"); 
Matcher m = pattern.matcher(text); 
Map<String, String> parserMap = new HashMap<>(); 

while (m.find()) { 
    String key = m.group(1); 
    String value = m.group(2); 
    parserMap.put(key, value); 
} 

IdeOne java working demo hを準備しました。 ERE:あなたは試合情報

Match 1 
    Group 1. 0-7  `appName` 
    Group 2. 8-11 `XXX` 

Match 2 
    Group 1. 12-20 `clientIp` 
    Group 2. 21-26 `X.X.X` 

Match 3 
    Group 1. 27-36 `timestamp` 
    Group 2. 37-64 `"2017-06-05T13:22:12-07:00"` 

Match 4 
    Group 1. 65-72 `request` 
    Group 2. 73-97 `"POST /forward HTTP/1.1"` 
+0

Guavaの 'Splitter.onPattern'は内部的に' Pattern'をコンパイルするスプリッタです。改善された 'String.split(String)'と考えてください。だから、元の質問は、 "これをString.split(String)で正しく行うにはどうしたらよいですか?"正規表現は同じです。 –

+0

@OlivierGrégoire、お勧めします。まあ、私の答えは、パターンを分割することに焦点を当てるのではなく、キー/値のパターンをキャプチャすることです。私はOPがそれらの値をキャプチャしたいと思います –

+0

確かに。 OPとは違って、解決策は何も想像していませんでした。 –

0

のサンプルを下に見ることができます

https://ideone.com/y8b8di

を、私は答えは、単一の正規表現で行うことができますわからないんだけど、ワーキング溶液をで作ることができます比較的容易:

parserMap = Splitter.onPattern("\\s(?=([^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)") 
    .omitEmptyStrings() 
    .splitToList(line) 
    .stream() 
    .collect(Collectors.toMap(
     s -> s.split("=", 2)[0], // the first part of split gets the key 
     s -> s.split("=", 2)[1] // everything else is the value 
    ) 
); 

splitのための正規表現を使用しようとのトラブルは、分割の本来の目的は、セパレータを見つけることだけであるということです。これは通常の正規表現の使用法とは異なります。ここでは、グループを使用して必要なものを選択することができます。あなたが分割するとき、あなたはが一致しないようにしようとしていますがほしいと思う、それは本当に乱雑になります。

関連する問題