Skip to content

Commit 462d69f

Browse files
committed
fix: 编码问题
1 parent 8fe8445 commit 462d69f

File tree

2 files changed

+50
-50
lines changed

2 files changed

+50
-50
lines changed

src/fuzzyMatch.ts

Lines changed: 38 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// ================ 类型定义 ================
1+
// ================ 类型定义 ================
22
interface MatchPosition {
33
start: number;
44
end: number;
@@ -9,7 +9,7 @@ interface NormalizedContent {
99
mapping: number[];
1010
}
1111

12-
// ================ 核心实现 ================
12+
// ================ 核心实现 ================
1313
const MAX_EDIT_DISTANCE = 5;
1414
const SEGMENT_COUNT = MAX_EDIT_DISTANCE + 1;
1515

@@ -18,42 +18,42 @@ export function applyFuzzyGlobalReplace(
1818
strOldContent: string,
1919
strNewContent: string
2020
): string {
21-
// 第二阶段:模糊匹配流程
21+
// 第二阶段:模糊匹配流程
2222
const { content: normContent, mapping } = normalizeContent(strContent);
2323
const pattern = normalizePattern(strOldContent);
2424

25-
// 分片查找候选位置
25+
// 分片查找候选位置
2626
const candidates = findCandidatePositions(normContent, pattern);
2727

28-
// 验证并获取有效匹配
28+
// 验证并获取有效匹配
2929
const matches = verifyMatches(normContent, pattern, candidates, mapping);
3030

3131
if (matches.length === 0) {
32-
throw new Error(`GLOBAL-REPLACE失败:未找到允许${MAX_EDIT_DISTANCE}个字符差异的匹配`);
32+
throw new Error(`GLOBAL-REPLACE失败:未找到允许${MAX_EDIT_DISTANCE}个字符差异的匹配`);
3333
}
3434

35-
// 应用替换
35+
// 应用替换
3636
return applyReplacements(strContent, matches, strNewContent);
3737
}
3838

39-
// ================ 算法核心模块 ================
39+
// ================ 算法核心模块 ================
4040
export function normalizeContent(original: string): { content: string; mapping: number[] } {
41-
// 第一步:去除注释
41+
// 第一步:去除注释
4242
const { content: noComments, mapping: mapping1 } = removeComments(original);
4343

44-
// 第二步:去除符号前后的空格
44+
// 第二步:去除符号前后的空格
4545
const { content: noSymbolSpaces, mapping: mapping2 } = removeSymbolSpaces(noComments);
4646

47-
// 第三步:将换行符改为空格,并合并连续的空格
47+
// 第三步:将换行符改为空格,并合并连续的空格
4848
const { content: finalContent, mapping: mapping3 } = normalizeWhitespace(noSymbolSpaces);
4949

50-
// 合并 mapping
50+
// 合并 mapping
5151
const finalMapping = mapping3.map(idx => mapping2[idx]).map(idx => mapping1[idx]);
5252

5353
return { content: finalContent, mapping: finalMapping };
5454
}
5555

56-
// 辅助函数1:去除注释,并确保 mapping 数组严格对应每个输出字符(包括换行符)
56+
// 辅助函数1:去除注释,并确保 mapping 数组严格对应每个输出字符(包括换行符)
5757
export function removeComments(original: string): { content: string; mapping: number[] } {
5858
const astrLines: string[] = original.split('\n');
5959
let strContent: string = "";
@@ -65,27 +65,27 @@ export function removeComments(original: string): { content: string; mapping: nu
6565
const nCommentIndex: number = strLine.indexOf('//');
6666
const strCleanLine: string = nCommentIndex !== -1 ? strLine.slice(0, nCommentIndex) : strLine;
6767

68-
// 添加清理后的行内容,并记录映射
68+
// 添加清理后的行内容,并记录映射
6969
strContent += strCleanLine;
7070
for (let nI: number = 0; nI < strCleanLine.length; nI++) {
7171
arrMapping.push(nCurrentPos + nI);
7272
}
7373

74-
// 只有在不是最后一行时添加换行符
74+
// 只有在不是最后一行时添加换行符
7575
if (i < astrLines.length - 1) {
7676
strContent += "\n";
7777
arrMapping.push(nCurrentPos + strLine.length);
78-
nCurrentPos += strLine.length + 1; // +1 表示换行符
78+
nCurrentPos += strLine.length + 1; // +1 表示换行符
7979
} else {
80-
nCurrentPos += strLine.length; // 最后一行没有换行符
80+
nCurrentPos += strLine.length; // 最后一行没有换行符
8181
}
8282
}
8383
return { content: strContent, mapping: arrMapping };
8484
}
8585

86-
// 辅助函数2:去除符号前后的空格
86+
// 辅助函数2:去除符号前后的空格
8787
export function removeSymbolSpaces(strContentIn: string): { content: string; mapping: number[] } {
88-
// 更新正则表达式,匹配常见符号
88+
// 更新正则表达式,匹配常见符号
8989
const regSymbols: RegExp = /[+\-/*()\[\]{};=,'"`!&|]/;
9090
let strNewContent: string = "";
9191
const arrMapping: number[] = [];
@@ -94,59 +94,59 @@ export function removeSymbolSpaces(strContentIn: string): { content: string; map
9494
for (let nI: number = 0; nI < nLen; nI++) {
9595
const strCurrentChar: string = strContentIn[nI];
9696

97-
// 使用正则表达式匹配所有空白字符(空格、制表符、换行符等)
97+
// 使用正则表达式匹配所有空白字符(空格、制表符、换行符等)
9898
if (/\s/.test(strCurrentChar) && strCurrentChar !== '\n') {
99-
// 查找向左第一个非空白字符
99+
// 查找向左第一个非空白字符
100100
let nPrev: number = nI - 1;
101101
while (nPrev >= 0 && /\s/.test(strContentIn[nPrev])) {
102102
nPrev--;
103103
}
104-
// 查找向右第一个非空白字符
104+
// 查找向右第一个非空白字符
105105
let nNext: number = nI + 1;
106106
while (nNext < nLen && /\s/.test(strContentIn[nNext])) {
107107
nNext++;
108108
}
109109

110110
let bSkipSpace: boolean = false;
111-
// 如果前一个字符是符号,跳过当前空白字符
111+
// 如果前一个字符是符号,跳过当前空白字符
112112
if (nPrev >= 0 && regSymbols.test(strContentIn[nPrev])) {
113113
bSkipSpace = true;
114114
}
115-
// 如果后一个字符是符号,跳过当前空白字符
115+
// 如果后一个字符是符号,跳过当前空白字符
116116
if (nNext < nLen && regSymbols.test(strContentIn[nNext])) {
117117
bSkipSpace = true;
118118
}
119119

120120
if (bSkipSpace) {
121-
continue; // 跳过符号附近的空白字符
121+
continue; // 跳过符号附近的空白字符
122122
}
123123
}
124124

125-
// 保留非空白字符或未跳过的空白字符
125+
// 保留非空白字符或未跳过的空白字符
126126
strNewContent += strCurrentChar;
127127
arrMapping.push(nI);
128128
}
129129

130130
return { content: strNewContent, mapping: arrMapping };
131131
}
132132

133-
// 辅助函数3:将换行符改为空格,并合并连续的空格
133+
// 辅助函数3:将换行符改为空格,并合并连续的空格
134134
export function normalizeWhitespace(content: string): { content: string; mapping: number[] }
135135
{
136136
let strNewContent: string = "";
137137
let arrMapping: number[] = [];
138-
let bAtLineStart: boolean = true; // 标记当前是否处于行首
139-
let nPendingSpaceIndex: number | null = null; // 待添加空格的原始索引
138+
let bAtLineStart: boolean = true; // 标记当前是否处于行首
139+
let nPendingSpaceIndex: number | null = null; // 待添加空格的原始索引
140140

141141
for (let nIdx = 0; nIdx < content.length; nIdx++)
142142
{
143143
const chChar: string = content[nIdx];
144144

145145
if (chChar === '\n')
146146
{
147-
// 遇到换行符时,丢弃待添加的空格(避免行尾空格)
147+
// 遇到换行符时,丢弃待添加的空格(避免行尾空格)
148148
nPendingSpaceIndex = null;
149-
// 如果输出为空或上一个字符不是换行符,则添加换行符
149+
// 如果输出为空或上一个字符不是换行符,则添加换行符
150150
if (strNewContent.length === 0 || strNewContent[strNewContent.length - 1] !== '\n')
151151
{
152152
strNewContent += '\n';
@@ -156,7 +156,7 @@ export function normalizeWhitespace(content: string): { content: string; mapping
156156
}
157157
else if (/\s/.test(chChar))
158158
{
159-
// 遇到非换行空白字符:如果在行首,则忽略;否则,记录第一个空白字符索引
159+
// 遇到非换行空白字符:如果在行首,则忽略;否则,记录第一个空白字符索引
160160
if (!bAtLineStart)
161161
{
162162
if (nPendingSpaceIndex === null)
@@ -167,7 +167,7 @@ export function normalizeWhitespace(content: string): { content: string; mapping
167167
}
168168
else
169169
{
170-
// 遇到非空白字符时,如果有待添加的空格则先输出一个空格
170+
// 遇到非空白字符时,如果有待添加的空格则先输出一个空格
171171
if (nPendingSpaceIndex !== null)
172172
{
173173
strNewContent += ' ';
@@ -235,13 +235,13 @@ export function verifyMatches(
235235
}
236236
});
237237

238-
// 如果找到了最佳候选,则用贪心方式扩展匹配范围
238+
// 如果找到了最佳候选,则用贪心方式扩展匹配范围
239239
if (bestMatch && bestCandidate !== -1)
240240
{
241241
let candidateIdx: number = bestCandidate;
242242
let patternIdx: number = 0;
243243
let startIndex: number = -1;
244-
// 从最佳候选起点开始,贪心扫描候选区域,遇到匹配的字符则同步推进模式串下标
244+
// 从最佳候选起点开始,贪心扫描候选区域,遇到匹配的字符则同步推进模式串下标
245245
while (candidateIdx < content.length && patternIdx < pattern.length)
246246
{
247247
if (content.charAt(candidateIdx) === pattern.charAt(patternIdx))
@@ -256,7 +256,7 @@ export function verifyMatches(
256256
}
257257

258258
let tmpMatch : MatchPosition = bestMatch;
259-
// nCandidateIdx 作为最终匹配结束位置(注意这里是最后一次匹配后加1的位置)
259+
// nCandidateIdx 作为最终匹配结束位置(注意这里是最后一次匹配后加1的位置)
260260
tmpMatch.start = mapping[startIndex];
261261
tmpMatch.end = mapping[Math.min(candidateIdx, content.length - 1)];
262262
bestMatch = tmpMatch;
@@ -265,7 +265,7 @@ export function verifyMatches(
265265
return bestMatch ? [bestMatch] : [];
266266
}
267267

268-
// ================ 工具函数 ================
268+
// ================ 工具函数 ================
269269
function splitPatternWithStart(pattern: string, count: number): { segment: string, start: number }[] {
270270
const segments: { segment: string, start: number }[] = [];
271271
const minSegmentLength = 3;
@@ -289,7 +289,7 @@ function calculateEditDistance(a: string, b: string, maxDistance: number): numbe
289289
return Infinity;
290290
}
291291

292-
// 使用滚动数组优化
292+
// 使用滚动数组优化
293293
let prevRow = Array(b.length + 1).fill(0).map((_, i) => i);
294294
let currentRow = new Array(b.length + 1);
295295

src/utiliti.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,41 +8,41 @@ export function activate(context: ExtensionContext) {
88
}
99

1010
/**
11-
* 读取文件并根据其编码(GBK、UTF-8 或带 BOM 的 UTF-8)转换为 UTF-8 字符串
12-
* @param filePath 文件路径
13-
* @returns 转换后的 UTF-8 字符串
14-
* @throws 如果无法读取文件或解码失败,抛出错误
11+
* 读取文件并根据其编码(GBK、UTF-8 或带 BOM 的 UTF-8)转换为 UTF-8 字符串
12+
* @param filePath 文件路径
13+
* @returns 转换后的 UTF-8 字符串
14+
* @throws 如果无法读取文件或解码失败,抛出错误
1515
*/
1616
export async function readFileAsUtf8(filePath: string): Promise<string> {
1717
try {
18-
// 读取文件的原始 Buffer
18+
// 读取文件的原始 Buffer
1919
const buffer = await fs.readFile(filePath);
2020

21-
// 检测是否为带 BOM 的 UTF-8
21+
// 检测是否为带 BOM 的 UTF-8
2222
const isUtf8WithBom =
2323
buffer.length >= 3 &&
2424
buffer[0] === 0xEF &&
2525
buffer[1] === 0xBB &&
2626
buffer[2] === 0xBF;
2727

2828
if (isUtf8WithBom) {
29-
// 移除 BOM 并作为 UTF-8 解码
29+
// 移除 BOM 并作为 UTF-8 解码
3030
return buffer.slice(3).toString('utf8');
3131
}
3232

33-
// 尝试作为 UTF-8 解码
33+
// 尝试作为 UTF-8 解码
3434
try {
35-
// 先验证是否是有效的 UTF-8
35+
// 先验证是否是有效的 UTF-8
3636
const utf8Text = buffer.toString('utf8');
37-
// 简单的 UTF-8 有效性检查:重新编码后比较
37+
// 简单的 UTF-8 有效性检查:重新编码后比较
3838
if (Buffer.from(utf8Text, 'utf8').equals(buffer)) {
3939
return utf8Text;
4040
}
4141
} catch (utf8Error) {
42-
// 如果 UTF-8 解码失败,继续尝试 GBK
42+
// 如果 UTF-8 解码失败,继续尝试 GBK
4343
}
4444

45-
// 尝试作为 GBK 解码
45+
// 尝试作为 GBK 解码
4646
try {
4747
const gbkText = iconv.decode(buffer, 'gbk');
4848
return gbkText;

0 commit comments

Comments
 (0)