Копиране и поставяне от excel, разлика между нов ред в клетка и разделител на ред

Трябва да предложим на нашите клиенти начин за копиране на excel в таблица в уеб приложение. Разделяме редове с нови редове и колони с табулиране.

Проблемът е, че в една клетка можете да имате нов ред, така че split(\n) просто ще разбере, че има нов ред.

    const rows = event.target.value.split('\n');
    for (let row of rows) {
      const values = row.split('\t');
    }

С кода по-горе, когато няма прекъсване на ред в клетките, можем да получим хубава таблица с копиране, но веднага щом има прекъсване на ред в клетките, всичко се премества на един ред и прекъсва всичко.

Как мога да различа нов ред за разделяне на редове и нов ред в клетки?


person Martin Paucot    schedule 31.05.2021    source източник


Отговори (1)


Помислете за малкия пример, където съм копирал данните от Excel в Notepad++ и можем да видим, че cat\nfish е цитиран:

въведете описание на изображението тук

Така че можете да третирате съдържанието, което се поставя в уеб приложението, като стойности, разделени с раздели (tsv) и да ги анализирате като такива.

Във фрагмента по-долу tsvStringToArray е адаптиран от тук (вижте тук също). Обърнете внимание, че се връща допълнителен ред поради този последен CR LF след dog. В реалния живот вероятно трябва да потърсите библиотека, която да направи това вместо вас. Може да гледате на D3 като на нещо, което може да работи в браузъра.

За arrToTable предполагам, че трябва да имате по-добро усилие от arrToTable. Трябва обаче да помислите дали трябва да пресъздадете новия ред в HTML.

const target = document.getElementById("input");
const output = document.getElementById("output");

const tsvStringToArray = (data) => {
  const re = /(\t|\r?\n|\r|^)(?:"([^"]*(?:""[^"]*)*)"|([^\t\r\n]*))/gi
  const result = [[]]
  let matches
  while ((matches = re.exec(data))) {
    if (matches[1].length && matches[1] !== "\t") result.push([])
    result[result.length - 1].push(
      matches[2] !== undefined ? matches[2].replace(/""/g, '"') : matches[3]
    )
  }
  //console.log(result);
  return result
}

const arrToTable = arr => {
  let tbl = document.createElement("table");
  for (row of arr) {
    let tr = document.createElement("tr");
    for (cell of row) {
      let td = document.createElement("td");
      let test = /\n/.test(cell);
      if (test) {
        let items = cell.split(/\n/);
        for ([idx, item] of items.entries()) {
          td.appendChild(document.createTextNode(item));
          if (idx < items.length) {
            td.appendChild(document.createElement("br"));
          }
        }
      } else {
        td.appendChild(document.createTextNode(cell));    
      }
      tr.appendChild(td);
    }
    tbl.appendChild(tr);
  }
  return tbl;
}

target.addEventListener("paste", e => {
  const text = event.clipboardData.getData("text");
  const arr = tsvStringToArray(text).slice(0, -1);
  const el = arrToTable(arr);
  output.appendChild(el);
});
div#input {
  height: 90px;
  width: 320px;
  background-color: powderblue;
}

table, tr, td {
  border: 1px solid black;
}
Paste in blue box:
<div id="input" contenteditable="true"></div>
<p>
<div id="output"></div>

person Robin Mackenzie    schedule 04.06.2021