该函数的目的是解析 CSV 文件的头部行(即第一行),并提取出所有的列名。CSV 文件是一种常用的文本格式,用于存储结构化数据,其中列与列之间通常用逗号分隔。有时,列名或列值中可能包含逗号,这时需要用双引号将整个列名或列值括起来,以确保正确的解析。
工作原理
正则表达式:
/"(?:[^"]|"")*"|,|\r\n|\n|\r/gm:
":匹配双引号,表示一个可能包含逗号的列名的开始或结束。(?:[^"]|"")*:匹配零个或多个非双引号字符,或者一个双引号字符(如果前一个字符也是双引号,则表示转义的双引号)。":匹配双引号,表示一个可能包含逗号的列名的结束。|:逻辑 “或” 操作符,用于匹配逗号、换行符等。,:匹配逗号,表示列与列之间的分隔符。\r\n|\n|\r:匹配行结束符,即回车符、换行符或回车换行符的组合。gm:g表示全局匹配,m表示多行匹配。解析逻辑:
- 初始化一个空数组
matches来存储解析出的列名。- 初始化一个变量
startIndex来记录上一个匹配的起始位置。- 使用
while循环和regex.exec(headerLine)来逐个匹配列名或分隔符。- 如果当前匹配的起始位置
match.index大于startIndex,则表示我们找到了一个新的列名(或列名的一部分)。将这部分内容添加到matches数组中。- 更新
startIndex为当前匹配的结束位置,即match.index + match[0].length。- 循环结束后,检查是否还有剩余的文本未被匹配。如果有,将其作为一个额外的列名添加到
matches数组中(这种情况可能发生在列名包含换行符时)。- 最后,返回
matches数组,其中包含了所有的列名。例子
假设
headerLine是a,"b,c",d。
- 正则表达式首先匹配到
a,然后是",接着是"b,c"(其中包含逗号),然后是",最后是,。- 在第一次循环中,
startIndex是 0,match.index是 1,所以match.index > startIndex成立。因此,"a"被添加到matches数组中。startIndex更新为 2(即match.index + match[0].length)。- 下一次循环匹配到
","b,c"和",但match.index(此时是 5)不大于startIndex(此时是 2),所以这部分不被添加到matches数组中。- 循环继续,匹配到
,,然后是d。- 最后,因为
startIndex(此时是 9)小于headerLine.length(此时是 10),所以"d"被添加到matches数组中。- 函数返回
matches数组,此时包含["a", "b,c", "d"]。这样,即使列名中包含逗号或换行符,函数也能正确地将它们解析为单独的列名
代码如下(可以直接调用):
const handleFileChange = (file) => {if (file && file.raw) {const reader = new FileReader();reader.onload = (e) => {const csvData = e.target.result;const lines = csvData.split('\n');if (lines.length > 0) {const header = parseHeader(lines[0]);columns.value = header; // 读取所有列名fileSelected.value = true;}};uploadFile1(file.raw);reader.readAsText(file.raw);}
};
const parseHeader = (headerLine) => {const regex = /"(?:[^"]|"")*"|,|\r\n|\n|\r/gm;let match;const matches = [];let startIndex = 0; // 记录上一个匹配的起始位置while ((match = regex.exec(headerLine)) !== null) {// 检查是否是列名的一部分if (match.index > startIndex) {// 添加之前匹配的列名matches.push(headerLine.substring(startIndex, match.index).replace(/""/g, '"'));}startIndex = match.index + match[0].length; // 更新下一个匹配的起始位置}// 添加最后一列(如果有的话)if (startIndex < headerLine.length) {matches.push(headerLine.substring(startIndex).replace(/""/g, '"'));}return matches;
};