fix: handle with comma (default and custom)

This commit is contained in:
JayBridge 2025-06-06 16:09:26 +08:00
parent bc3ad2399e
commit 978a4b0619
5 changed files with 95 additions and 20 deletions

View file

@ -12,6 +12,13 @@ export const enUS = {
placeholder: 'Edit selected cell...'
},
csv: {
error: 'Error'
error: 'Error',
parsingFailed: 'Failed to parse CSV. Please check file format.'
},
settings: {
fieldSeparator: 'Field Separator',
fieldSeparatorDesc: 'The character used to separate fields (e.g., comma, semicolon, tab)',
quoteChar: 'Quote Character',
quoteCharDesc: 'Character used to enclose fields containing special characters'
}
};

View file

@ -12,6 +12,13 @@ export const zhCN = {
placeholder: '编辑选中单元格...'
},
csv: {
error: '错误'
error: '错误',
parsingFailed: 'CSV解析失败请检查文件格式'
},
settings: {
fieldSeparator: '字段分隔符',
fieldSeparatorDesc: '用于分隔字段的字符(例如:逗号、分号、制表符)',
quoteChar: '引号字符',
quoteCharDesc: '用于包围含有特殊字符的字段'
}
};

View file

@ -1,21 +1,25 @@
import * as Papa from 'papaparse';
import { Notice } from 'obsidian';
import { i18n } from '../i18n';
export interface CSVParseConfig {
header: boolean;
dynamicTyping: boolean;
skipEmptyLines: boolean;
delimiter?: string;
quoteChar?: string;
quoteChar: string;
escapeChar: string;
}
export class CSVUtils {
// 默认解析配置
// 现在这是默认设置的唯一权威来源
static defaultConfig: CSVParseConfig = {
header: false,
dynamicTyping: false,
skipEmptyLines: false,
quoteChar: '"'
delimiter: ',',
quoteChar: '"', // 关键这是修复报告bug的关键
escapeChar: '"',
};
/**
@ -34,8 +38,8 @@ export class CSVUtils {
return parseResult.data as string[][];
} catch (error) {
console.error("CSV解析错误:", error);
new Notice("CSV解析失败请检查文件格式");
return [[""]]; // 返回一个空表格
new Notice(`${i18n.t('csv.error')}: CSV解析失败请检查文件格式`);
return [[""]];
}
}
@ -60,12 +64,14 @@ export class CSVUtils {
// 找出最大列数
let maxCols = 0;
for (const row of tableData) {
maxCols = Math.max(maxCols, row.length);
if (row) {
maxCols = Math.max(maxCols, row.length);
}
}
// 确保每行都有相同的列数
const normalizedData = tableData.map(row => {
const newRow = [...row];
const newRow = row ? [...row] : [];
while (newRow.length < maxCols) {
newRow.push("");
}

View file

@ -1,4 +1,4 @@
import { TextFileView, ButtonComponent, Notice, DropdownComponent, getIcon, IconName } from "obsidian";
import { TextFileView, ButtonComponent, Notice, DropdownComponent, getIcon, IconName, Setting } from "obsidian";
import { CSVUtils, CSVParseConfig } from './utils/csv-utils';
import { TableHistoryManager } from './utils/history-manager';
import { TableUtils } from './utils/table-utils';
@ -20,12 +20,9 @@ export class CSVView extends TextFileView {
private columnWidths: number[] = [];
private autoResize: boolean = true;
// Papa Parse 配置选项
private papaConfig: CSVParseConfig = {
header: false,
dynamicTyping: false,
skipEmptyLines: false
};
// 新增:解析器设置状态
private delimiter: string = ',';
private quoteChar: string = '"';
// 编辑栏
private editBarEl: HTMLElement;
@ -78,8 +75,11 @@ getIcon(): IconName {
setViewData(data: string, clear: boolean) {
try {
// 使用工具类解析CSV数据
this.tableData = CSVUtils.parseCSV(data, this.papaConfig);
// 使用新的分隔符设置解析CSV数据
this.tableData = CSVUtils.parseCSV(data, {
delimiter: this.delimiter,
quoteChar: this.quoteChar
});
// 确保至少有一行一列
if (!this.tableData || this.tableData.length === 0) {
@ -107,6 +107,13 @@ getIcon(): IconName {
}
}
// 新增:重新解析和刷新视图的方法
private reparseAndRefresh() {
// 获取原始数据并用新设置重新解析
const rawData = this.data;
this.setViewData(rawData, false); // 重新运行setViewData但不清除历史
}
refresh() {
// Safety check: ensure tableEl exists
if (!this.tableEl) {
@ -352,6 +359,34 @@ getIcon(): IconName {
// 创建操作区
this.operationEl = this.contentEl.createEl("div", { cls: "csv-operations" });
// 新增解析器设置UI
const parserSettingsEl = this.operationEl.createEl("div", { cls: "csv-parser-settings" });
new Setting(parserSettingsEl)
.setName("字段分隔符")
.setDesc("用于分隔字段的字符(例如:逗号、分号、制表符)")
.addText(text => {
text.setValue(this.delimiter)
.setPlaceholder("例如:, 或 ; 或 \\t 表示制表符")
.onChange(async (value) => {
// 处理制表符的特殊情况
this.delimiter = value === '\\t' ? '\t' : value;
this.reparseAndRefresh();
});
});
new Setting(parserSettingsEl)
.setName("引号字符")
.setDesc("用于包围含有特殊字符的字段")
.addText(text => {
text.setValue(this.quoteChar)
.setPlaceholder('默认为双引号 "')
.onChange(async (value) => {
this.quoteChar = value || '"';
this.reparseAndRefresh();
});
});
// 创建操作按钮容器
const buttonContainer = this.operationEl.createEl("div", { cls: "csv-operation-buttons" });
@ -456,8 +491,6 @@ getIcon(): IconName {
// 初始化时刷新视图
this.refresh();
// 添加样式
// this.addStyles();
} catch (error) {
console.error("Error in onOpen:", error);
new Notice(`Failed to open CSV view: ${error.message}`);

View file

@ -164,4 +164,26 @@ If your plugin does not need CSS, delete this file.
color: var(--text-on-accent);
}
/* 解析器设置样式 */
.csv-parser-settings {
margin-bottom: 16px;
padding: 12px;
border: 1px solid var(--background-modifier-border);
border-radius: 6px;
background-color: var(--background-secondary);
}
.csv-parser-settings .setting-item {
border: none;
padding: 8px 0;
}
.csv-parser-settings .setting-item-info {
margin-right: 16px;
}
.csv-parser-settings .setting-item-control input {
max-width: 200px;
}