【问题标题】:Split (break apart) merged table cells in google spreadsheet with an apps script使用应用程序脚本在 Google 电子表格中拆分(拆分)合并的表格单元格
【发布时间】:2013-03-15 20:33:35
【问题描述】:

在操作(复制/移动)包含合并单元格的范围时,我总是收到错误“您的粘贴与合并的单元格重叠。请取消合并单元格,然后重试”。但是当尝试使用Range#breakApart 取消合并范围内的单元格时,我收到另一个错误:“无法合并选定的单元格。”,这更加令人困惑,因为我没有尝试合并任何内容,我只是在尝试将细胞分开。

【问题讨论】:

  • SpreadsheetApp.getActive().getActiveSheet().getDataRange().breakApart();

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


【解决方案1】:

原来breakApart 仅在调用它的范围包含所有合并的单元格时才有效,而不仅仅是合并区域的一部分。

这不会太糟糕。一旦您意识到 API 中无法获取合并单元格的范围,问题就开始了。所以解决这个问题的最好方法(到目前为止我发现)只是轻轻地扩大你的范围,直到没有错误发生:

var breakRange = myRange;
for(;;) {
  try {
    breakRange.breakApart();
    break;
  } catch(e) {
    breakRange = mySheet.getRange(
      breakRange.getRowIndex(),
      breakRange.getColumnIndex(),
      Math.min(
        breakRange.getHeight()+5,
        mySheet.getMaxRows()-breakRange.getRowIndex()+1
      ),
      Math.min(
        breakRange.getWidth()+5,
        mySheet.getMaxColumns()-breakRange.getColumnIndex()+1
      )
    );
  }
}

(我添加了五行/列而不是一个,因为获取范围似乎是一个相当昂贵的过程)。只要您在扩展搜索区域时没有添加额外的合并单元格,这就会非常有效。

当涉及到电子表格中的合并单元格时,Google Apps Scripts API 从根本上至少在以下方面被破坏了:

  1. 无法获取工作表/范围中合并单元格范围的数组。
  2. 应该有一种方法可以查看哪些单元格已被拆分(breakApart 仅返回原始范围“用于链接”)。这使得无法拆分合并,然后让每个单元格包含原始合并单元格的内容。
  3. 尝试在仅包含部分合并单元格的范围内使用 breakApart 仍应拆分整个合并而不是引发异常。

总而言之,目前的 API 仅适用于其布局和使用由脚本作者自己完全控制的电子表格。

【讨论】:

  • 这种尝试/捕获方法的聪明想法......以及相关的 cmets 也是如此。 +1 & 谢谢 // 注意:你不应该在扩大区域时检查最大列和最大行参数吗?
  • @Sergeinsas 谢谢,我更新了我的帖子以包含您的建议。
【解决方案2】:

此函数将与提供的单元格或范围部分相交的合并单元格的范围分开。 正如 Adam Morris (@clssrmtechtools) 在此 thread 中所建议的那样,它使用表格高级服务来识别给定表格中的所有合并范围。

演示电子表格here

/** 
* Breaks apart merged cells in range
* @param {sheet} sheet Sheet of range
* @param {range} rangeToSplit Cell or cells that intersect with whole merged range
*/
function breakApartAux(sheet, rangeToSplit) {

  // Current spreadsheet & sheet
  let ss = SpreadsheetApp.getActiveSpreadsheet();
  let activeSSId = ss.getId();
  let activeSId = sheet.getSheetId();

  // Get sheet's merges using advanced sheets service
  let merges = Sheets.Spreadsheets.get(activeSSId).sheets.find(s => s.properties.sheetId == activeSId).merges;

  if (merges == undefined) SpreadsheetApp.getUi().alert('No merged cells found in sheet.');
  else {

    // Logger.log(merges);

    // Cells to merge R/C
    let rowS = rangeToSplit.getRow();
    let rowE = rowS + rangeToSplit.getNumRows() - 1;
    let colS = rangeToSplit.getColumn();
    let colE = colS + rangeToSplit.getNumColumns() - 1;

    // Find overlapping merged range
    // Advanced service merged ranges start in 0 and are right-open [..)
    let merge = merges.find(m => {
                            let mRowS = m.startRowIndex + 1;
                            let mRowE = m.endRowIndex;
                            let mColS = m.startColumnIndex + 1;
                            let mColE = m.endColumnIndex;

                            // Check for overlapping
                            return ((rowS >= mRowS && rowS <= mRowE)  || 
                                    (rowE <= mRowE && rowE >= mRowS)  ||
                                    (rowS < mRowS && rowE > mRowE)) &&
                                   ((colS >= mColS && colS <= mColE)  ||
                                    (colE <= mColE && colE >= mColS)  ||
                                    (colS < mColS && colE > mColE));
    })

    // Overlapping range?
    if (merge == undefined) SpreadsheetApp.getUi().alert('No merged cells found in specified range.');
    else {
      // Break apart whole range
      ss.getActiveSheet().getRange(merge.startRowIndex + 1,
                                   merge.startColumnIndex + 1,
                                   merge.endRowIndex - merge.startRowIndex,
                                   merge.endColumnIndex - merge.startColumnIndex).breakApart();
    }
  }

}

【讨论】:

【解决方案3】:

这是我找到的最简单的方法:

function unmerge() {
  var sheetName = 'Sheet1';   // Change!
  var a1Notation = 'A1:B15';  // Change!  
  var range = SpreadsheetApp.getActive().getSheetByName(sheetName).getRange(a1Notation);  
  var mergedRanges = range.getMergedRanges();
  for (var i = 0; i < mergedRanges.length; i++)
  {
    mergedRanges[i].breakApart();
  }
}

【讨论】:

    【解决方案4】:

    受 Raphael 回答的启发,这是取消合并工作表中所有单元格的方法。这是我用于合并具有相邻空值的单元格的数据导入的内容,即我将单元格 a1 与单元格 b1 取消合并,其中 a1 有一个值而 b1 没有:

    function unmergeSheet() {
    
    let mySheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
    let myRange = mySheet.getDataRange()
    myRange.breakApart();
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
    }
    

    更新了 Juuso Nykänen 的建议

    【讨论】:

    • var breakRange = myRange;可以直接省略myRange.breakApart();
    猜你喜欢
    • 2018-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    相关资源
    最近更新 更多