当您从Excel复制列并粘贴到textarea元素中时,您会得到制表符分隔的字符串.并且同一行的单元格的值现在用制表符分隔.

我需要在JavaScript中获取所有单元格的值.理论上的方法很简单:

  1. Split将字符串转换为行数组,指定\n作为分隔符.
  2. 通过指定\t作为分隔符,将每行拆分为列array.

但在实践中,这有一定的困难,因为一个单元格也可以包含一个或多个选项卡.因此,在步骤2中直接指定\t作为分隔符可能会产生错误的结果.

我提出的一个解决方案是,首先用自定义字符串(如__TAB__)替换单元格中的每个制表符;然后安全地执行第一步和第二步;最后将所有__TAB__替换回制表符.

由于包含制表符或多行的单元格值在粘贴到textarea元素中时会自动包含在两个双引号(")中,因此需要使用正则表达式来查找这些字符串.

我找到的一个正则表达式是this one.但是,它不能处理包含制表符的单元格值.我try 通过如下方式修改它来修复它:

var rows = pastedText.replace(/(^|\t)"((?:(?:""|[^"])*(?:\r\n|\n\r|\n|\r|\t))+(?:""|[^"])*)"(\t|$)/mg, function (match, p1, p2, p3) {
    // This function runs for each cell with multi lined text.
    return p1 + p2
        // Replace any double double-quotes with a single
        // double-quote
        .replace(/""/g, '"')
        // Replacing any tab with a custom string
        .replace(/\t/g, '__TAB__') + p3;
})
// Split each line into rows
.split(/\r\n|\n\r|\n|\r/g);

它运行得很好,直到遇到such pasted text个.粘贴的文本表示一个20行、3列的数据,其中某些行为空.

浏览器在处理这类粘贴的文本时会无限期地无响应(在最新的Firefox 120.0.1和Chrome 120.0.6099.71中进行了测试).主要原因是第6行和第2列的单元格的开头包含一个".

我们的目标是获得每个单元的价值,如果有更好的解决方案,我真的不需要坚持一种类型的解决方案.如有任何建议,我们不胜感激.每个单元格可以包含一行或多行、一个或多个制表符、甚至一个或多个直双引号.

推荐答案

以下正则表达式将匹配带引号的单元格(可能是多行,可能包含制表符)或简单单元格(可能包含双引号):

/(?<=^|(\t))(?=.)(?:"((?:""|[^"])*)"|[^\t\r\n]*)(?=\t|$)/gm

它有两个捕获组来帮助识别我们在哪种情况下.

下面是一个简单的演示,您可以在其中粘贴文本区域,并以JSON格式显示结果(请注意,在JSON呈现中,双引号用反斜杠转义):

function convertTsv(tsv) {
    const regex = /(?<=^|(\t))(?=.)(?:"((?:""|[^"])*)"|[^\t\r\n]*)(?=\t|$)/gm;
    const data = [];
    for (const [all, sep, quoted] of tsv.matchAll(regex)) {
        if (!sep) data.push([]); // New row
        data.at(-1).push(quoted === undefined ? all : quoted.replaceAll('""', '"'));
    }
    return data;
}

function padColumns(data) {
    const length = Math.max(...data.map(row => row.length));
    return data.map(row => Array.from({length}, (_, i) => row[i] ?? ""));
}

function refresh() {
    const tsv = document.querySelector("textarea").value;
    const data = padColumns(convertTsv(tsv));
    document.querySelector("pre").textContent = JSON.stringify(data, null, 2);
}

document.querySelector("textarea").addEventListener("input", refresh);
refresh();
textarea { width: 100%; height: 5em }
<textarea>This is a test    " quote at start
"Multiline
text"   "Multiline 
with tab     in it"
    
above row is empty  
Next cell is empty  
    previous cell is empty
</textarea>

<pre>
</pre>

Javascript相关问答推荐

setFinder关闭模式并重定向到url

追踪执行顺序

使用NgDeliverentOutlet和动态内容投影的Angular 渲染组件

Fastify错误:CORS策略已阻止从起源api-dev.example.com上的MLhttp请求

JavaScript:循环访问不断变化的数组中的元素

在时间轴完整日历中显示日期标题

有Angular 的material .未应用收件箱中的价值变化

对象和数字减法会抵消浏览器js中的数字

从实时数据库(Firebase)上的子类别读取数据

硬币兑换运行超时

使用下表中所示的值初始化一个二维数组

给定一个凸多边形作为一组边,如何根据到最近边的距离填充里面的区域

未捕获错误:[]:getActivePinia()被调用,但没有活动Pinia.🍍""在调用app.use(pinia)之前,您是否try 使用store ?""

JavaScript是否有多个`unfined`?

NG/Express API路由处理程序停止工作

在画布中调整边上反弹框的大小失败

打字脚本中方括号符号属性访问和拾取实用程序的区别

AG-GRIDreact 显示布尔值而不是复选框

使用createBrowserRoutVS BrowserRouter的Reaction路由

我无法在Api Reaction本机上发出GET请求