【问题标题】:Google sheets split multi-line cell into new rows (+ duplicate surrounding row entries)Google 表格将多行单元格拆分为新行(+ 重复周围的行条目)
【发布时间】:2021-12-07 10:40:02
【问题描述】:

我有一个夏令营网站。 每次注册都会自动出现在谷歌表格中。 我想将注册分成多行。

我为这个项目继承的 Google 电子表格包括一个 C - H 列,在同一个单元格中列出了多个子信息,由换行符分隔(即 CHAR(10) )。每行有一个注册。单元格(C 到 H 列)中的行数逐行变化。我的初始工作表如下所示:

我需要执行以下操作来优化此工作表:

拆分每个多行单元格,以便每个子项出现在自己的行中。这要求在原始行下方插入新行。 复制原始行上所有其他单元格的数据(即来自 A 和 J:V 列),以便每个新行都包含一个子项的完整数据。 我需要一个自动化流程 - 我需要处理大约 3000 个注册,因此无法通过任何手动步骤来完成。

工作表应如下所示:

我尝试在 google 表格中使用此自定义脚本,但没有成功:

function result(range) {
  var splitCol = 1; // split on column B
  var output2 = [];
  for(var i=0, iLen=range.length; i<iLen; i++) {
    var s = range[i][splitCol].split("\n");    
    for(var j=0, jLen=s.length; j<jLen; j++) {
      var output1 = []; 
      for(var k=0, kLen=range[0].length; k<kLen; k++) {
        if(k == splitCol) {
          output1.push(s[j]);
        } else {
          output1.push(range[i][k]);
        }
      }
      output2.push(output1);
    }    
  }
  return output2;
}

欢迎所有帮助!谢谢。

【问题讨论】:

  • 你需要比“不起作用”更具描述性

标签: google-apps-script google-sheets google-sheets-formula


【解决方案1】:

试试下面的custom function。它逐行循环,并在具有最多分隔值的行中的单元格中插入与分隔符分隔的值一样多的行。

该函数复制行,以便每个拆分值都在自己的行中。不包含分隔符的列将使用原始行中的值填充。

/**
* Expands data by splitting text strings that contain a separator character.
*
* Duplicates rows so that each split value is in its own row.
* Columns that do not contain the separator character are filled down
* using the value in the original row.
*
* @param {A2:D42} data The rows to expand.
* @param {char(10)} separator The character to split by.
* @customfunction
*/
function ExpandSplit(data, separator = '\n') {
  // version 1.1, written by --Hyde, 7 December 2021
  //  - support multiple split columns
  //  - see https://stackoverflow.com/q/70258670/13045193
  if (!Array.isArray(data)) {
    throw new Error('ExpandSplit expected data to be a range or multiple rows.');
  }
  let expanded = [];
  data.forEach(row => {
    const numDupRows = Math.max(1, ...row.map(column => typeof column === 'string' && column.split(separator).length));
    const duplicates = [];
    row.forEach((column, columnIndex) => {
      const splitString = String(column).split(separator);
      for (let dupRow = 0; dupRow < numDupRows; dupRow++) {
        if (!duplicates[dupRow]) {
          duplicates[dupRow] = [];
        }
        if (typeof column === 'string' && splitString.length > 1) {
          duplicates[dupRow][columnIndex] = splitString[dupRow] || null;
        } else {
          duplicates[dupRow][columnIndex] = column;
        }
      }
    });
    expanded = expanded.concat(duplicates);
  });
  return expanded;
}

【讨论】:

    【解决方案2】:

    您可以将此代码用作指南。它只是采用给定的范围并将其细分为找到\n 分隔符的尽可能多的行。

    const splitData = () => {
      let ss = SpreadsheetApp.openById(SS_ID).getSheets()[0]
      let rangeToSplit = ss.getRange('C2:H2')
      let values = rangeToSplit.getValues()[0]
      for(let i = 0 ; i < values.length; i++){
        var cellValues = values[i].split('\n')
        for ( let j = 0 ; j < cellValues.length ; j++) {
          // 2+j refers to the rows 2,3,..
          // 3+i refers to columns C,D,...
          ss.getRange(2+j, 3+i).setValue(cellValues[j])
        }
      }
    }
    

    如果您想容纳此代码来复制不包含换行符的单元格,您应该尝试添加某种控制机制,例如:

    var content = ss.getRange(2 + j, 1 + i).getValue()
        if (content.split('\n').length != 1) {
          ss.getRange(2 + j, 3 + i).setValue(cellValues[j])
    }
    

    2021 年 10 月 12 日更新

    根据@doubleunary 的建议,我决定测试batch operations

    /**
     * A workaround using batch operations
     * @param {Array} resulting of the getRange().getValues()
     * @returns {Array} filtered by \n
     */
    const batchUpdate = (data) => {
      var result = []
      for (var i = 0; i < data.length; i++) {
        var check  = data[i].some(element=>element.includes('\n'))
        if (check) {
          var copyArr = data[i].slice()
          /// temp the cells to split
          var tempC = data[i][2].split('\n')
          var tempD = data[i][3].split('\n')
          var tempE = data[i][4].split('\n')
          var tempF = data[i][5].split('\n')
          var tempG = data[i][6].split('\n')
          var tempH = data[i][7].split('\n')
          for (var j = 0; j < tempC.length; j++) {
            copyArr[2] = tempC[j]
            copyArr[3] = tempD[j]
            copyArr[4] = tempE[j]
            copyArr[5] = tempF[j]
            copyArr[6] = tempG[j]
            copyArr[7] = tempH[j]
            result.push([data[i][0],data[i][1],temp[j],data[i][3],data[i][4]])
          }
        } else {
          result.push(data[i])
        }
      }
      return result
    }
    
    const testingBatch = () => {
      // 
      let rangeValues = ss.getRange('A2:J300').getValues()
      var newValues = batchUpdate(rangeValues)
      console.log(newValues)
      ss.getRange(2,1, newValues.length, newValues[0].length).setValues(newValues)
    }
    
    
    文档:

    【讨论】:

    • Hmm... OP 指定了“3000 个注册”,因此该代码将需要 long 时间来运行,因为它一次获取和设置一个单元格的值。见Apps Script best practices
    猜你喜欢
    • 2020-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-28
    相关资源
    最近更新 更多