Google Apps Script: Как работать с диапазонами в Google Таблицах?

Работа с данными в Google Таблицах с помощью Google Apps Script неизбежно связана с понятием диапазона (Range). Эффективное манипулирование диапазонами — ключ к автоматизации большинства задач, от простого чтения/записи данных до сложной обработки и форматирования.

Что такое диапазон в Google Таблицах и зачем он нужен

Диапазон — это ссылка на одну или несколько ячеек на листе Google Таблицы. Это может быть одна ячейка, строка, столбец или прямоугольная область ячеек. Диапазоны являются основным объектом для взаимодействия скриптов с данными таблицы. С их помощью мы можем:

Читать значения из ячеек.

Записывать новые значения.

Применять форматирование (цвет, шрифт, границы).

Управлять структурой (вставка/удаление строк/столбцов).

Выполнять другие операции (очистка, копирование, перемещение).

Основные понятия: ячейка, строка, столбец, диапазон

Ячейка (Cell): Минимальная единица таблицы, расположенная на пересечении строки и столбца (например, A1, B2).

Строка (Row): Горизонтальный ряд ячеек (например, строка 1, строка 5).

Столбец (Column): Вертикальный ряд ячеек (например, столбец A, столбец C).

Диапазон (Range): Прямоугольная область, включающая одну или несколько ячеек. Определяется либо адресом (A1:C5), либо координатами (строка 1, столбец 1, 5 строк, 3 столбца).

Получение доступа к Google Таблице и листу (Spreadsheet, Sheet)

Прежде чем работать с диапазонами, необходимо получить доступ к самой таблице и конкретному листу. Стандартный способ:

/**
 * Получает активный лист текущей Google Таблицы.
 * @returns {GoogleAppsScript.Spreadsheet.Sheet} Активный лист.
 * @throws {Error} Если не удается получить доступ к таблице или листу.
 */
function getActiveSheet(): GoogleAppsScript.Spreadsheet.Sheet {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  if (!ss) {
    throw new Error("Не удалось получить активную таблицу.");
  }
  const sheet = ss.getActiveSheet();
  if (!sheet) {
    throw new Error("Не удалось получить активный лист.");
  }
  return sheet;
}

// Пример использования
function main() {
  try {
    const sheet: GoogleAppsScript.Spreadsheet.Sheet = getActiveSheet();
    Logger.log(`Активный лист: ${sheet.getName()}`);
    // Дальнейшая работа с листом...
  } catch (error) {
    Logger.log(`Ошибка: ${error.message}`);
  }
}

Получение диапазонов в Google Таблицах

Класс Sheet предоставляет несколько методов для получения объекта Range.

getRange() — основной метод получения диапазона

Метод getRange() является универсальным и имеет несколько перегруженных версий для различных сценариев.

Получение диапазона по A1 нотации (например, ‘A1:C5’)

Наиболее распространенный способ — использование A1 нотации, знакомой пользователям Google Таблиц.

/**
 * Получает диапазон данных рекламной кампании по A1 нотации.
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet - Лист Google Таблицы.
 * @returns {GoogleAppsScript.Spreadsheet.Range} Диапазон с данными.
 */
function getCampaignDataRangeA1(sheet: GoogleAppsScript.Spreadsheet.Sheet): GoogleAppsScript.Spreadsheet.Range {
  // Предполагаем, что данные кампании (Дата, Клики, Показы, Стоимость) находятся в A2:D100
  const rangeA1Notation: string = 'A2:D100';
  return sheet.getRange(rangeA1Notation);
}

// Пример использования
function demoGetRangeA1() {
  const sheet = getActiveSheet();
  const campaignRange = getCampaignDataRangeA1(sheet);
  Logger.log(`Диапазон получен: ${campaignRange.getA1Notation()}`);
}

Получение диапазона по номерам строк и столбцов (getRow(), getColumn(), getNumRows(), getNumColumns())

Этот способ удобен при динамическом определении диапазона или при работе с индексами строк/столбцов.

getRange(row, column): Получает одну ячейку.

getRange(row, column, numRows): Получает столбец или его часть, начиная с row, column, высотой numRows.

getRange(row, column, numRows, numColumns): Получает прямоугольный диапазон.

/**
 * Получает диапазон метрик (Клики, Показы) для первых 10 строк данных.
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet - Лист Google Таблицы.
 * @returns {GoogleAppsScript.Spreadsheet.Range} Диапазон с метриками.
 */
function getMetricsRangeByCoords(sheet: GoogleAppsScript.Spreadsheet.Sheet): GoogleAppsScript.Spreadsheet.Range {
  const startRow: number = 2; // Первая строка данных (после заголовка)
  const clicksColumn: number = 2; // Столбец B (Клики)
  const impressionsColumn: number = 3; // Столбец C (Показы)
  const numRowsToGet: number = 10;
  const numColumnsToGet: number = 2; // Клики и Показы

  // Получаем диапазон B2:C11
  return sheet.getRange(startRow, clicksColumn, numRowsToGet, numColumnsToGet);
}

// Пример использования
function demoGetRangeCoords() {
  const sheet = getActiveSheet();
  const metricsRange = getMetricsRangeByCoords(sheet);
  Logger.log(`Диапазон метрик: ${metricsRange.getA1Notation()}`);
}

Получение последнего заполненного диапазона (getLastRow(), getLastColumn())

Часто необходимо обработать все данные на листе. Методы getLastRow() и getLastColumn() возвращают номер последней строки и столбца, содержащих данные.

/**
 * Получает весь диапазон с данными на листе, начиная с A1.
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet - Лист Google Таблицы.
 * @returns {GoogleAppsScript.Spreadsheet.Range | null} Диапазон данных или null, если лист пуст.
 */
function getDataRegion(sheet: GoogleAppsScript.Spreadsheet.Sheet): GoogleAppsScript.Spreadsheet.Range | null {
  const lastRow: number = sheet.getLastRow();
  const lastCol: number = sheet.getLastColumn();

  if (lastRow === 0 || lastCol === 0) {
    // Лист пуст
    return null;
  }

  return sheet.getRange(1, 1, lastRow, lastCol);
}

// Пример использования
function demoGetDataRegion() {
  const sheet = getActiveSheet();
  const dataRange = getDataRegion(sheet);
  if (dataRange) {
    Logger.log(`Весь диапазон данных: ${dataRange.getA1Notation()}`);
  } else {
    Logger.log('Лист пуст.');
  }
}

Чтение данных из диапазона

После получения объекта Range можно читать из него данные.

getValue() — получение значения одной ячейки

Возвращает значение одной ячейки. Если метод вызван для диапазона из нескольких ячеек, вернется значение левой верхней ячейки.

/**
 * Читает заголовок первого столбца (A1).
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet - Лист.
 * @returns {any} Значение ячейки A1.
 */
function readFirstHeader(sheet: GoogleAppsScript.Spreadsheet.Sheet): any {
  const cell: GoogleAppsScript.Spreadsheet.Range = sheet.getRange('A1');
  return cell.getValue();
}

getValues() — получение значений из диапазона в виде двумерного массива

Возвращает двумерный массив (Object[][]), где каждый вложенный массив представляет строку данных. Это наиболее эффективный способ чтения больших объемов данных, так как он требует одного вызова API.

/**
 * Читает данные рекламной кампании (например, из A2:D) и возвращает их как массив.
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet - Лист.
 * @returns {Object[][]} Двумерный массив данных.
 */
function readCampaignData(sheet: GoogleAppsScript.Spreadsheet.Sheet): Object[][] {
  const lastRow = sheet.getLastRow();
  if (lastRow < 2) {
    return []; // Нет данных для чтения (только заголовок или пусто)
  }
  // Предполагаем 4 столбца данных: Дата, Клики, Показы, Стоимость
  const range = sheet.getRange(2, 1, lastRow - 1, 4); // A2:D
  return range.getValues();
}

// Пример использования
function demoReadData() {
  const sheet = getActiveSheet();
  const data: Object[][] = readCampaignData(sheet);
  if (data.length > 0) {
    Logger.log(`Прочитано строк данных: ${data.length}`);
    // Пример обработки: вывод первой строки данных
    Logger.log(`Первая строка: ${JSON.stringify(data[0])}`);
  } else {
    Logger.log('Нет данных для чтения.');
  }
}
Реклама

Примеры чтения данных различных типов (текст, числа, даты)

getValues() возвращает данные в их естественных типах JavaScript:

Текст: string

Числа: number

Даты/Время: Date object

Булево: boolean

Пустые ячейки: '' (пустая строка)

function processReadData() {
  const sheet = getActiveSheet();
  const data: Object[][] = readCampaignData(sheet);

  data.forEach((row, index) => {
    const dateVal: any = row[0];
    const clicks: any = row[1];
    const cost: any = row[3];

    if (dateVal instanceof Date) {
      Logger.log(`Строка ${index + 2}: Дата ${dateVal.toLocaleDateString()}`);
    }
    if (typeof clicks === 'number' && typeof cost === 'number' && clicks > 0) {
      const cpc = cost / clicks;
      Logger.log(`Строка ${index + 2}: CPC = ${cpc.toFixed(2)}`);
    }
  });
}

Особенности обработки пустых ячеек

Как упомянуто, getValues() возвращает пустую строку '' для пустых ячеек. Важно учитывать это при проверках и вычислениях, чтобы избежать ошибок, например, при делении на ноль или при проверке на null/undefined.

Запись данных в диапазон

Запись данных так же важна, как и чтение.

setValue() — запись значения в одну ячейку

Записывает одно значение. Если вызван для диапазона из нескольких ячеек, значение будет записано во все ячейки диапазона.

/**
 * Записывает текущую дату и время в ячейку F1.
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet - Лист.
 */
function setTimestamp(sheet: GoogleAppsScript.Spreadsheet.Sheet): void {
  const cell: GoogleAppsScript.Spreadsheet.Range = sheet.getRange('F1');
  cell.setValue(new Date());
}

setValues() — запись значений в диапазон из двумерного массива

Записывает данные из двумерного массива Object[][] в указанный диапазон. Размеры массива должны точно совпадать с размерами целевого диапазона. Это самый эффективный способ записи множества данных.

/**
 * Рассчитывает CTR и записывает его в столбец E для существующих данных.
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet - Лист.
 */
function calculateAndWriteCTR(sheet: GoogleAppsScript.Spreadsheet.Sheet): void {
  const lastRow = sheet.getLastRow();
  if (lastRow < 2) return; // Нет данных

  // Читаем Клики (столбец B) и Показы (столбец C)
  const dataRange = sheet.getRange(2, 2, lastRow - 1, 2); // B2:C
  const values: Object[][] = dataRange.getValues();

  const ctrResults: Object[][] = [];

  values.forEach(row => {
    const clicks: number = Number(row[0]) || 0;
    const impressions: number = Number(row[1]) || 0;
    let ctr: number | string = 0;
    if (impressions > 0) {
      ctr = clicks / impressions;
    } else {
      ctr = 'N/A'; // Или 0, в зависимости от требований
    }
    ctrResults.push([ctr]); // Массив для записи должен быть двумерным
  });

  // Определяем целевой диапазон для записи CTR (столбец E)
  const targetRange = sheet.getRange(2, 5, ctrResults.length, 1); // E2:E

  // Устанавливаем формат (процентный)
  targetRange.setNumberFormat('0.00%');

  // Записываем результаты
  targetRange.setValues(ctrResults);
}

// Пример использования
function demoWriteCTR() {
  const sheet = getActiveSheet();
  calculateAndWriteCTR(sheet);
  Logger.log('Расчет и запись CTR завершены.');
}

Примеры записи данных различных типов

setValues() принимает массив, элементы которого могут быть типа string, number, boolean или Date. Google Apps Script автоматически преобразует их в соответствующие форматы ячеек (хотя иногда может потребоваться явное форматирование с помощью setNumberFormat() и т.д.).

Автоматическое изменение размера диапазона перед записью (setValues)

Важно помнить: setValues() не изменяет размер листа или диапазона автоматически для соответствия размеру входного массива. Размеры передаваемого массива данных Object[][] должны строго совпадать с размерами диапазона, полученного через getRange(). Если размеры не совпадают, будет выброшено исключение.

Например, если getRange('A1:B2') (2×2), то и массив для setValues() должен быть [[val1, val2], [val3, val4]].

Операции с диапазонами: форматирование и другие действия

Объект Range предоставляет множество методов для форматирования и управления структурой.

Изменение формата ячеек (цвет фона, шрифт, выравнивание)

/**
 * Форматирует заголовки таблицы (первая строка).
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet - Лист.
 */
function formatHeaders(sheet: GoogleAppsScript.Spreadsheet.Sheet): void {
  const lastCol: number = sheet.getLastColumn();
  if (lastCol === 0) return;

  const headerRange: GoogleAppsScript.Spreadsheet.Range = sheet.getRange(1, 1, 1, lastCol);

  headerRange
    .setBackground('#4a86e8') // Синий фон
    .setFontColor('white')
    .setFontWeight('bold')
    .setHorizontalAlignment('center')
    .setVerticalAlignment('middle');
}

// Пример использования
function demoFormat() {
  const sheet = getActiveSheet();
  formatHeaders(sheet);
  Logger.log('Заголовки отформатированы.');
}

Другие популярные методы форматирования:

setFontFamily(fontFamily)

setFontSize(size)

setFontLine('underline' | 'line-through' | 'none')

setNumberFormat(formatString)

setBorder(top, left, bottom, right, vertical, horizontal, color, style)

setWrap(isWrapEnabled)

Удаление и вставка строк/столбцов в диапазоне

insertCells(shiftDimension): Вставляет ячейки, сдвигая существующие (вправо или вниз).

deleteCells(shiftDimension): Удаляет ячейки, сдвигая существующие (влево или вверх).

insertRows(howMany), insertColumns(howMany): Вставляют строки/столбцы перед/слева от диапазона.

deleteRows(rowPosition, howMany), deleteColumns(columnPosition, howMany): Удаляют строки/столбцы, на которых находится диапазон.

/**
 * Вставляет пустую строку перед строкой 5.
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet - Лист.
 */
function insertRowExample(sheet: GoogleAppsScript.Spreadsheet.Sheet): void {
  sheet.insertRowsBefore(5, 1);
  Logger.log('Строка вставлена перед 5-й строкой.');
}

/**
 * Удаляет столбец C.
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet - Лист.
 */
function deleteColumnExample(sheet: GoogleAppsScript.Spreadsheet.Sheet): void {
  // Столбец C имеет индекс 3
  sheet.deleteColumn(3);
  Logger.log('Столбец C удален.');
}

Копирование и перемещение диапазонов

copyTo(destinationRange, options): Копирует данные и форматирование.

moveTo(targetRange): Перемещает диапазон (вырезать и вставить).

/**
 * Копирует заголовки на другой лист 'Backup'.
 * @param {GoogleAppsScript.Spreadsheet.Spreadsheet} ss - Таблица.
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sourceSheet - Исходный лист.
 */
function copyHeadersToBackup(ss: GoogleAppsScript.Spreadsheet.Spreadsheet, sourceSheet: GoogleAppsScript.Spreadsheet.Sheet): void {
  let backupSheet = ss.getSheetByName('Backup');
  if (!backupSheet) {
    backupSheet = ss.insertSheet('Backup');
  }

  const lastCol = sourceSheet.getLastColumn();
  if (lastCol === 0) return;

  const sourceHeaders = sourceSheet.getRange(1, 1, 1, lastCol);
  const destination = backupSheet.getRange('A1');

  sourceHeaders.copyTo(destination);
  Logger.log('Заголовки скопированы на лист Backup.');
}

Очистка содержимого диапазона (clearContent()) и форматирования (clearFormat())

clearContent(): Удаляет только значения, оставляя форматирование.

clearFormat(): Удаляет только форматирование, оставляя значения.

clear(options): Позволяет гибко настроить очистку (содержимое, формат, примечания, проверки данных и т.д.).

/**
 * Очищает данные о CTR (столбец E), но сохраняет формат.
 * @param {GoogleAppsScript.Spreadsheet.Sheet} sheet - Лист.
 */
function clearCtrData(sheet: GoogleAppsScript.Spreadsheet.Sheet): void {
  const lastRow = sheet.getLastRow();
  if (lastRow < 2) return;

  const ctrRange = sheet.getRange(2, 5, lastRow - 1, 1); // E2:E
  ctrRange.clearContent();
  Logger.log('Данные CTR очищены.');
}

Работа с диапазонами — фундаментальный навык при разработке скриптов для Google Таблиц. Понимание методов getRange, getValues, setValues и операций форматирования/структуры открывает широкие возможности для автоматизации анализа данных, отчетности и управления информацией.


Добавить комментарий