Skip to content

Commit 4a32310

Browse files
committed
✨ [lmt] 新增了str_human_trim和human_space_regex
1 parent 77676c4 commit 4a32310

File tree

2 files changed

+126
-59
lines changed

2 files changed

+126
-59
lines changed

util/src/string.test.ts

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,53 @@
1-
import { str_trim_indent } from "./string.ts";
1+
import { str_human_space, str_human_trim, str_trim_indent } from "./string.ts";
22
import assert from "node:assert";
33

44
Deno.test("str_trim_indent", () => {
5-
assert.equal(
6-
str_trim_indent(`
5+
assert.equal(
6+
str_trim_indent(`
77
1111
88
111
99
1010
11
1111
`),
12-
` 1111
12+
` 1111
1313
111
1414
15-
11`
16-
);
17-
assert.equal(str_trim_indent(` `), ``);
18-
assert.equal(str_trim_indent(`
15+
11`,
16+
);
17+
assert.equal(str_trim_indent(` `), ``);
18+
assert.equal(
19+
str_trim_indent(`
1920
a
20-
`), `a`);
21+
`),
22+
`a`,
23+
);
24+
});
25+
26+
Deno.test("str_human_trim", () => {
27+
// 基本空格测试
28+
assert.equal(str_human_trim(" hello "), "hello");
29+
assert.equal(str_human_trim("\nhello\n"), "hello");
30+
assert.equal(str_human_trim("\r\nhello\r\n"), "hello");
31+
32+
// 混合空格测试
33+
assert.equal(str_human_trim(" \n \r\n hello \n \r\n "), "hello");
34+
35+
// Unicode空格测试
36+
assert.equal(str_human_trim("\u200B\u200Chello\u200D\u200E"), "hello");
37+
assert.equal(str_human_trim("\u2000hello\u2000"), "hello");
38+
39+
// 空字符串测试
40+
assert.equal(str_human_trim(""), "");
41+
assert.equal(str_human_trim(" "), "");
42+
assert.equal(str_human_trim("\n\r\n\u200B"), "");
43+
44+
// 测试所有定义的空格字符
45+
const allSpaces = [...str_human_space].join("");
46+
assert.equal(str_human_trim(allSpaces + "hello" + allSpaces), "hello");
47+
48+
// 保留中间的空格
49+
assert.equal(str_human_trim(" hello world "), "hello world");
50+
51+
// 不同语言的文本测试
52+
assert.equal(str_human_trim(" Hello世界こんにちは "), "Hello世界こんにちは");
2153
});

util/src/string.ts

Lines changed: 85 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,110 @@
1+
import { func_remember } from "./func.ts";
2+
13
/**
24
* 反转字符串
35
*/
46
export const str_reverse = (str: string): string => {
5-
let restr = "";
6-
/// 不能用 i++ < length 迭代,会有Unicode字符问题
7-
for (const char of str) {
8-
restr = char + restr;
9-
}
10-
return restr;
7+
let restr = "";
8+
/// 不能用 i++ < length 迭代,会有Unicode字符问题
9+
for (const char of str) {
10+
restr = char + restr;
11+
}
12+
return restr;
1113
};
1214

1315
/**
1416
* 寻找字符串开头是否指定字符串,是的话,进行替换
1517
*/
1618
export const str_replace_start = (
17-
str: string,
18-
searchValue: string,
19-
replaceValue: string
19+
str: string,
20+
searchValue: string,
21+
replaceValue: string,
2022
): string => {
21-
if (str.startsWith(searchValue)) {
22-
return replaceValue + str.slice(searchValue.length);
23-
}
24-
return str;
23+
if (str.startsWith(searchValue)) {
24+
return replaceValue + str.slice(searchValue.length);
25+
}
26+
return str;
2527
};
2628

2729
/**
2830
* 寻找字符串结尾是否指定字符串,是的话,进行替换
2931
*/
3032
export const str_replace_end = (
31-
str: string,
32-
searchValue: string,
33-
replaceValue: string
33+
str: string,
34+
searchValue: string,
35+
replaceValue: string,
3436
): string => {
35-
if (str.endsWith(searchValue)) {
36-
return str.slice(0, -searchValue.length) + replaceValue;
37-
}
38-
return str;
37+
if (str.endsWith(searchValue)) {
38+
return str.slice(0, -searchValue.length) + replaceValue;
39+
}
40+
return str;
3941
};
4042

4143
export const str_trim_indent: (str: string) => string = (str: string) => {
42-
const lines = str.split("\n");
43-
let min = -1;
44-
const lines2 = lines.map((line) => {
45-
const line2 = line.trimStart();
46-
/// 寻找非空的
47-
if (line2.length !== 0) {
48-
const start_len = line.length - line2.length;
49-
if (min === -1) {
50-
min = start_len;
51-
} else {
52-
min = Math.min(min, start_len);
53-
}
54-
return line;
44+
const lines = str.split("\n");
45+
let min = -1;
46+
const lines2 = lines.map((line) => {
47+
const line2 = line.trimStart();
48+
/// 寻找非空的
49+
if (line2.length !== 0) {
50+
const start_len = line.length - line2.length;
51+
if (min === -1) {
52+
min = start_len;
53+
} else {
54+
min = Math.min(min, start_len);
55+
}
56+
return line;
57+
}
58+
return line2;
59+
});
60+
if (min === -1) {
61+
return "";
5562
}
56-
return line2;
57-
});
58-
if (min === -1) {
59-
return "";
60-
}
61-
if (min === 0) {
62-
return lines2.join("\n");
63-
}
64-
let result = "";
65-
for (const line of lines2) {
66-
// 如果已经有内容,那么要新增一行就要先加一个换行符
67-
if (result.length > 0) {
68-
result += "\n";
63+
if (min === 0) {
64+
return lines2.join("\n");
6965
}
70-
if (line.length > 0) {
71-
result += line.slice(min);
66+
let result = "";
67+
for (const line of lines2) {
68+
// 如果已经有内容,那么要新增一行就要先加一个换行符
69+
if (result.length > 0) {
70+
result += "\n";
71+
}
72+
if (line.length > 0) {
73+
result += line.slice(min);
74+
}
7275
}
73-
}
74-
return result.trimEnd();
76+
return result.trimEnd();
77+
};
78+
79+
/** 对于人类来说是空格的字符 */
80+
export const str_human_space = new Set([
81+
"\u0020",
82+
"\u00A0",
83+
"\u1680",
84+
"\u2000",
85+
"\u200B",
86+
"\u200C",
87+
"\u200D",
88+
"\u200E",
89+
"\u200F",
90+
"\u202A",
91+
"\u000A",
92+
"\u000D",
93+
"\u2028",
94+
"\u2029",
95+
]);
96+
97+
// 创建一个正则表达式字符串,使用 Set 中的字符
98+
export const human_space_regex = func_remember(() => {
99+
const pattern = [...str_human_space].map((ch) => ch.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
100+
return {
101+
start: new RegExp(`^(?:${pattern})+`),
102+
end: new RegExp(`(?:${pattern})+$`),
103+
all: new RegExp(`(?:${pattern})+`, "g"),
104+
};
105+
});
106+
107+
export const str_human_trim = (str: string): string => {
108+
const regex = human_space_regex();
109+
return str.replace(regex.start, "").replace(regex.end, "");
75110
};

0 commit comments

Comments
 (0)