mirror of
https://github.com/liubinfighter/csv-lite.git
synced 2026-07-22 05:43:52 +00:00
fix: handle with comma (default and custom)
This commit is contained in:
parent
bc3ad2399e
commit
978a4b0619
5 changed files with 95 additions and 20 deletions
|
|
@ -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'
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,6 +12,13 @@ export const zhCN = {
|
|||
placeholder: '编辑选中单元格...'
|
||||
},
|
||||
csv: {
|
||||
error: '错误'
|
||||
error: '错误',
|
||||
parsingFailed: 'CSV解析失败,请检查文件格式'
|
||||
},
|
||||
settings: {
|
||||
fieldSeparator: '字段分隔符',
|
||||
fieldSeparatorDesc: '用于分隔字段的字符(例如:逗号、分号、制表符)',
|
||||
quoteChar: '引号字符',
|
||||
quoteCharDesc: '用于包围含有特殊字符的字段'
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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("");
|
||||
}
|
||||
|
|
|
|||
55
src/view.ts
55
src/view.ts
|
|
@ -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}`);
|
||||
|
|
|
|||
22
styles.css
22
styles.css
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue