自学内容网 自学内容网

Vue处理CSV列名包含逗号问题

该函数的目的是解析 CSV 文件的头部行(即第一行),并提取出所有的列名。CSV 文件是一种常用的文本格式,用于存储结构化数据,其中列与列之间通常用逗号分隔。有时,列名或列值中可能包含逗号,这时需要用双引号将整个列名或列值括起来,以确保正确的解析。

工作原理

  1. 正则表达式

    • /"(?:[^"]|"")*"|,|\r\n|\n|\r/gm
      • ":匹配双引号,表示一个可能包含逗号的列名的开始或结束。
      • (?:[^"]|"")*:匹配零个或多个非双引号字符,或者一个双引号字符(如果前一个字符也是双引号,则表示转义的双引号)。
      • ":匹配双引号,表示一个可能包含逗号的列名的结束。
      • |:逻辑 “或” 操作符,用于匹配逗号、换行符等。
      • ,:匹配逗号,表示列与列之间的分隔符。
      • \r\n|\n|\r:匹配行结束符,即回车符、换行符或回车换行符的组合。
      • gmg 表示全局匹配,m 表示多行匹配。
  2. 解析逻辑

    • 初始化一个空数组 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;
};

原文地址:https://blog.csdn.net/m0_64694079/article/details/144797672

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!