Whatsapp 将历史解析为对话框 json
Whatsapp parse history to dialog json
所以我有这个 Whatsapp 日志文件,看起来像这样:(时间戳不准确)
[15.11.16, 16:13:29] Person A: Hello
[15.11.16, 16:13:45] Person B: This is
a multiline
message
[15.11.16, 16:14:12] Person A: Wow, so cool
我想将它们解析成如下所示的 json 格式:
{
"msg": [
{
"sender": "Person A",
"message": "Hello",
"time": 1479205511000,
"response": {
"sender": "Person B",
"message": "This is\na multiline\nmessage",
"time": 1479205536000
}
},
...
]
}
更重要的是,首先消息将分为三个部分:
- 时间(作为时间戳)
- 人名
- 消息(如果是多行消息,需要转义换行符)
发生的另一件事是响应,它选择一个主要人物(在本例中 "Person A")。然后它从顶部开始查看每条消息,查找该人(称为 "Main-Message")的第一条消息。如果它找到一个,它将寻找另一个人的响应(下一条消息(称为"Response"))。如果下一条消息再次来自主要人物,它将选择该消息作为 "Main-Message" 并寻找下一条消息。
示例:
Person A: Hi
Person B: Hi
Person A: This is cool
Person A: I am cool
Person B: Ah ok
在这个例子中,我们将选择 "Person A" 作为我们的主角。第一条消息是由我们的主要人物撰写的,因此它将是我们的主要消息。下一条消息来自其他人,因此这将是我们的回复。
{
"sender":"Person A",
"message":"Hi",
"time":1479205511000,
"response":{
"sender":"Person B",
"message":"Hi",
"time":1479205536000
}
}
下一条消息又是我们的主要人物,所以我们就把它作为我们的主要消息。但是之后的消息是 not 的,所以我们将跳过之前的消息。 之后的信息又是我们对手,所以这就是我们的回应。
{
"sender":"Person A",
"message":"I am cool",
"time":1479205511000,
"response":{
"sender":"Person B",
"message":"Ah ok",
"time":1479205536000
}
}
我们现在有一个 JSON 这样的:
{
"msg":[
{
"sender":"Person A",
"message":"Hi",
"time":1479205511000,
"response":{
"sender":"Person B",
"message":"Hi",
"time":1479205536000
}
},
{
"sender":"Person A",
"message":"I am cool",
"time":1479205511000,
"response":{
"sender":"Person B",
"message":"Ah ok",
"time":1479205536000
}
}
]
}
有几个问题:
- 多行消息
- 应该转义的非 UTF-8 字符,例如 '' -> 文本编码
- 巨大的日志(最多 100.000 行)-> 性能
- 有时这些行以控制字符开头,所以像 String.startsWith 这样的东西并不总是完美
您可能已经从我的标签中猜到了,我使用的语言是 Java。
如有任何疑问或不清楚的信息,请随时提请我注意。
我自己做的。首先,我做了一个 Class 命名为 "Message":
public class Message {
public String sender;
public String time;
public String message;
public String plainMessage;
public Message(String line) {
String[] array = line.split("]");
time = clean(array[0].replace("[", ""));
array = Main.removeElements(array, array[0]);
line = Main.join("]", array);
array = line.split(":");
sender = clean(array[0]);
array = Main.removeElements(array, array[0]);
line = Main.join(":", array);
plainMessage = line;
line = StringEscapeUtils.escapeJava(line);
line = escapeUmlaut(line);
message = StringEscapeUtils.escapeJson(line);
}
private String escapeUmlaut(String input) {
String output = input.replace("ü", "ue")
.replace("ö", "oe")
.replace("ä", "ae")
.replace("ß", "ss");
output = output.replace("Ü(?=[a-zäöüß ])", "Ue")
.replace("Ö(?=[a-zäöüß ])", "Oe")
.replace("Ä(?=[a-zäöüß ])", "Ae");
output = output.replace("Ü", "UE")
.replace("Ö", "OE")
.replace("Ä", "AE");
return output;
}
public static String clean(String what) {
char[] chars = what.toCharArray();
what = "";
char[] allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890[](){}=?!\§$%&/'#*+;,:.-_<>|".toCharArray();
for (char c : chars) {
for (char cc : allowed) {
if (cc == c) {
what += c;
}
}
}
return what;
}
}
这个Class有解析消息的任务。
这就是我们合并多行消息的方式:
ArrayList <String> parsed = new ArrayList <String> ();
for (int x = 0; x < size; x++) {
String line = list.get(x);
if (startsWith(line, '[')) {
parsed.add(line);
} else {
int lastn = parsed.size() - 1;
String last = parsed.get(lastn);
last += "\n" + line;
parsed.set(lastn, last);
}
}
这是 Class 的用法:
Message MainMessage = null;
String json = "";
boolean firstWrite = false;
final Pattern pattern = Pattern.compile("[a-zA-Z0-9]+", Pattern.MULTILINE);
for (int x = 0; x < size; x++) {
result = "";
progressBar.setValue(x);
String line = parsed.get(x);
if (config.debug) {
System.out.println(line);
}
Message message = new Message(line);
final Matcher matcher = pattern.matcher(message.plainMessage);
if (!matcher.find()) {
continue;
}
if (x == 0 && mainSender == null) {
mainSender = message.sender;
MainMessage = message;
continue;
}
if (mainSender.equals(message.sender)) {
MainMessage = message;
} else if (message.sender != mainSender && MainMessage != null) {
json = "\n{\"sender\": \"" + MainMessage.sender + "\", \"message\": \"" + MainMessage.message + "\", \"response\": ";
json += "{\"sender\": \"" + message.sender + "\", \"message\": \"" + message.message + "\"}}";
if (firstWrite) {
json = "," + json;
}
Files.write(Paths.get(
export), json.getBytes(), StandardOpenOption.APPEND);
json = "";
MainMessage = null;
firstWrite = true;
}
}
所以我有这个 Whatsapp 日志文件,看起来像这样:(时间戳不准确)
[15.11.16, 16:13:29] Person A: Hello
[15.11.16, 16:13:45] Person B: This is
a multiline
message
[15.11.16, 16:14:12] Person A: Wow, so cool
我想将它们解析成如下所示的 json 格式:
{
"msg": [
{
"sender": "Person A",
"message": "Hello",
"time": 1479205511000,
"response": {
"sender": "Person B",
"message": "This is\na multiline\nmessage",
"time": 1479205536000
}
},
...
]
}
更重要的是,首先消息将分为三个部分:
- 时间(作为时间戳)
- 人名
- 消息(如果是多行消息,需要转义换行符)
发生的另一件事是响应,它选择一个主要人物(在本例中 "Person A")。然后它从顶部开始查看每条消息,查找该人(称为 "Main-Message")的第一条消息。如果它找到一个,它将寻找另一个人的响应(下一条消息(称为"Response"))。如果下一条消息再次来自主要人物,它将选择该消息作为 "Main-Message" 并寻找下一条消息。
示例:
Person A: Hi
Person B: Hi
Person A: This is cool
Person A: I am cool
Person B: Ah ok
在这个例子中,我们将选择 "Person A" 作为我们的主角。第一条消息是由我们的主要人物撰写的,因此它将是我们的主要消息。下一条消息来自其他人,因此这将是我们的回复。
{
"sender":"Person A",
"message":"Hi",
"time":1479205511000,
"response":{
"sender":"Person B",
"message":"Hi",
"time":1479205536000
}
}
下一条消息又是我们的主要人物,所以我们就把它作为我们的主要消息。但是之后的消息是 not 的,所以我们将跳过之前的消息。 之后的信息又是我们对手,所以这就是我们的回应。
{
"sender":"Person A",
"message":"I am cool",
"time":1479205511000,
"response":{
"sender":"Person B",
"message":"Ah ok",
"time":1479205536000
}
}
我们现在有一个 JSON 这样的:
{
"msg":[
{
"sender":"Person A",
"message":"Hi",
"time":1479205511000,
"response":{
"sender":"Person B",
"message":"Hi",
"time":1479205536000
}
},
{
"sender":"Person A",
"message":"I am cool",
"time":1479205511000,
"response":{
"sender":"Person B",
"message":"Ah ok",
"time":1479205536000
}
}
]
}
有几个问题:
- 多行消息
- 应该转义的非 UTF-8 字符,例如 '' -> 文本编码
- 巨大的日志(最多 100.000 行)-> 性能
- 有时这些行以控制字符开头,所以像 String.startsWith 这样的东西并不总是完美
您可能已经从我的标签中猜到了,我使用的语言是 Java。
如有任何疑问或不清楚的信息,请随时提请我注意。
我自己做的。首先,我做了一个 Class 命名为 "Message":
public class Message {
public String sender;
public String time;
public String message;
public String plainMessage;
public Message(String line) {
String[] array = line.split("]");
time = clean(array[0].replace("[", ""));
array = Main.removeElements(array, array[0]);
line = Main.join("]", array);
array = line.split(":");
sender = clean(array[0]);
array = Main.removeElements(array, array[0]);
line = Main.join(":", array);
plainMessage = line;
line = StringEscapeUtils.escapeJava(line);
line = escapeUmlaut(line);
message = StringEscapeUtils.escapeJson(line);
}
private String escapeUmlaut(String input) {
String output = input.replace("ü", "ue")
.replace("ö", "oe")
.replace("ä", "ae")
.replace("ß", "ss");
output = output.replace("Ü(?=[a-zäöüß ])", "Ue")
.replace("Ö(?=[a-zäöüß ])", "Oe")
.replace("Ä(?=[a-zäöüß ])", "Ae");
output = output.replace("Ü", "UE")
.replace("Ö", "OE")
.replace("Ä", "AE");
return output;
}
public static String clean(String what) {
char[] chars = what.toCharArray();
what = "";
char[] allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890[](){}=?!\§$%&/'#*+;,:.-_<>|".toCharArray();
for (char c : chars) {
for (char cc : allowed) {
if (cc == c) {
what += c;
}
}
}
return what;
}
}
这个Class有解析消息的任务。
这就是我们合并多行消息的方式:
ArrayList <String> parsed = new ArrayList <String> ();
for (int x = 0; x < size; x++) {
String line = list.get(x);
if (startsWith(line, '[')) {
parsed.add(line);
} else {
int lastn = parsed.size() - 1;
String last = parsed.get(lastn);
last += "\n" + line;
parsed.set(lastn, last);
}
}
这是 Class 的用法:
Message MainMessage = null;
String json = "";
boolean firstWrite = false;
final Pattern pattern = Pattern.compile("[a-zA-Z0-9]+", Pattern.MULTILINE);
for (int x = 0; x < size; x++) {
result = "";
progressBar.setValue(x);
String line = parsed.get(x);
if (config.debug) {
System.out.println(line);
}
Message message = new Message(line);
final Matcher matcher = pattern.matcher(message.plainMessage);
if (!matcher.find()) {
continue;
}
if (x == 0 && mainSender == null) {
mainSender = message.sender;
MainMessage = message;
continue;
}
if (mainSender.equals(message.sender)) {
MainMessage = message;
} else if (message.sender != mainSender && MainMessage != null) {
json = "\n{\"sender\": \"" + MainMessage.sender + "\", \"message\": \"" + MainMessage.message + "\", \"response\": ";
json += "{\"sender\": \"" + message.sender + "\", \"message\": \"" + message.message + "\"}}";
if (firstWrite) {
json = "," + json;
}
Files.write(Paths.get(
export), json.getBytes(), StandardOpenOption.APPEND);
json = "";
MainMessage = null;
firstWrite = true;
}
}