Скопируйте и вставьте из 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