-
Notifications
You must be signed in to change notification settings - Fork 35
/
string_util.js
192 lines (168 loc) · 5.84 KB
/
string_util.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/**
* Only support caret notations (^C, ^H, ^U, ^[, ^?, ...)
* If you want to show \ and ^, use \\ and \^ respectively
*/
export function unescapeStr(it) {
var result = '';
for (var i = 0; i < it.length; ++i) {
var curChar = it.charAt(i);
var nextChar = it.charAt(i+1);
if (i == it.length - 1) {
result += curChar;
break;
}
if (curChar == '\\' && (nextChar == '\\' || nextChar == '^')) {
result += nextChar;
} else if (curChar == '^') {
if ('@' <= nextChar && nextChar <= '_') {
var code = it.charCodeAt(i+1) - 64;
result += String.fromCharCode(code);
i++;
} else if (nextChar == '?') {
result += '\x7f';
i++;
} else {
result += '^';
}
} else {
result += curChar;
}
}
return result;
};
// Wrap text within maxLen without hyphenating English words,
// where the maxLen is generally the screen width.
export function wrapText(it, maxLen, enterChar) {
// Divide string into non-hyphenated groups
// classified as \r, \n, single full-width character, an English word,
// and space characters in the beginning of original line. (indent)
// Spaces next to a word group are merged into that group
// to ensure the start of each wrapped line is a word.
// FIXME: full-width punctuation marks aren't recognized
var pattern = /\r|\n|([^\x00-\x7f][,.?!:;]?[\t ]*)|([\x00-\x08\x0b\x0c\x0e-\x1f\x21-\x7f]+[\t ]*)|[\t ]+/g;
var splited = it.match(pattern);
var result = '';
var len = 0;
for (var i = 0; i < splited.length; ++i) {
// Convert special characters to spaces with the same width
// and then we can get the width by the length of the converted string
var grouplen = splited[i].replace(/[^\x00-\x7f]/g," ")
.replace(/\t/," ")
.replace(/\r|\n/,"")
.length;
if (splited[i] == '\r' || splited[i] == '\n')
len = 0;
if (len + grouplen > maxLen) {
result += enterChar;
len = 0;
}
result += splited[i];
len += grouplen;
}
return result;
};
export function u2b(it) {
var data = '';
for (var i = 0; i < it.length; ++i) {
if (it.charAt(i) < '\x80') {
data += it.charAt(i);
continue;
}
var pos = it.charCodeAt(i);
var hi = lib.u2bArray[2*pos], lo = lib.u2bArray[2*pos+1];
if (hi || lo)
data += String.fromCharCode(hi) + String.fromCharCode(lo);
else // Not a big5 char
data += '\xFF\xFD';
}
return data;
};
export function b2u(it) {
var str = '';
for (var i = 0; i < it.length; ++i) {
if (it.charAt(i) < '\x80' || i == it.length-1) {
str += it.charAt(i);
continue;
}
var pos = it.charCodeAt(i) << 8 | it.charCodeAt(i+1);
var code = lib.b2uArray[2*pos] << 8 | lib.b2uArray[2*pos+1];
if (code) {
str += String.fromCharCode(code);
++i;
} else { // Not a big5 char
str += it.charAt(i);
}
}
return str;
};
export function isDBCSLead(ch) {
let code = ch.charCodeAt(0);
return code >= 0x81 && code <= 0xfe;
};
export function parseReplyText(it) {
return (it.indexOf('▲ 回應至 (F)看板 (M)作者信箱 (B)二者皆是 (Q)取消?[F] ') === 0 ||
it.indexOf('▲ 無法回應至看板。 改回應至 (M)作者信箱 (Q)取消?[Q]') === 0 ||
it.indexOf('把這篇文章收入到暫存檔?[y/N]') === 0 ||
it.indexOf('請選擇暫存檔 (0-9)[0]:') === 0);
};
export function parsePushInitText(it) {
return (it.indexOf('您覺得這篇文章 ') === 0 ||
it.search(/→ \w+ *: +/) === 0 ||
it.indexOf('很抱歉, 本板不開放回覆文章,要改回信給作者嗎? [y/N]:') === 0);
};
export function parseReqNotMetText(it) {
return (it.indexOf(' ◆ 未達看板發文限制:') === 0);
};
export function parseStatusRow(str) {
var regex = new RegExp(/ 瀏覽 第 (\d{1,3})(?:\/(\d{1,3}))? 頁 *\( *(\d{1,3})%\) 目前顯示: 第 0*(\d+)~0*(\d+) 行 *(?:\(y\)回應)?(?:\(X\/?%\)推文)?(?:\(h\)說明)? *\(←\/?q?\)離開 /g);
var result = regex.exec(str);
if (result && result.length === 6) {
return {
pageIndex: parseInt(result[1]),
pageTotal: parseInt(result[2]),
pagePercent: parseInt(result[3]),
rowIndexStart: parseInt(result[4]),
rowIndexEnd: parseInt(result[5])
};
}
return null;
};
export function parseListRow(str) {
var regex = new RegExp(/\[\d{1,2}\/\d{1,2} +星期. +\d{1,2}:\d{1,2}\] .+ 線上\d+人, 我是\w+ +\[呼叫器\](?:關閉|打開) /g);
return regex.test(str);
};
export function parseWaterball(str) {
var regex = new RegExp(/\x1b\[1;33;46m\u2605(\w+)\x1b\[0;1;37;45m (.+) \x1b\[m\x1b\[K/g);
var result = regex.exec(str);
if (result && result.length == 3) {
return { userId: result[1], message: result[2] };
} else {
regex = new RegExp(/\x1b\[24;\d{2}H\x1b\[1;37;45m([^\x1b]+)(?:\x1b\[24;18H)?\x1b\[m/g);
result = regex.exec(str);
if (result && result.length == 2) {
return { message: result[1] };
}
}
return null;
};
export function ansiHalfColorConv(it) {
var str = '';
var regex = new RegExp('\x15\\[(([0-9]+)?;)+50m', 'g');
var result = null;
var indices = [];
while ((result = regex.exec(it))) {
indices.push(result.index + result[0].length - 4);
}
if (indices.length === 0) {
return it;
}
var curInd = 0;
for (var i = 0; i < indices.length; ++i) {
var ind = indices[i];
var preEscInd = it.substring(curInd, ind).lastIndexOf('\x15') + curInd;
str += it.substring(curInd, preEscInd) + '\x00' + it.substring(ind+4, ind+5) + it.substring(preEscInd, ind) + 'm';
curInd = ind+5;
}
str += it.substring(curInd);
return str;
};