Google Apps Script: Как проверить и удалить данные?

Google Apps Script предоставляет мощные инструменты для автоматизации работы с данными в Google Workspace, включая Google Sheets. Проверка и удаление данных являются критически важными задачами для поддержания чистоты, точности и актуальности информации, особенно при работе с большими объемами данных, например, в маркетинговых кампаниях, списках лидов или отчетах веб-аналитики.

Зачем проверять и удалять данные?

Точность данных: Обеспечение соответствия данных ожидаемым форматам и значениям (например, проверка email-адресов, числовых диапазонов).

Актуальность: Удаление устаревшей или нерелевантной информации.

Производительность: Уменьшение объема данных может ускорить обработку и расчеты в таблицах.

Устранение дубликатов: Исключение повторной информации, которая может исказить аналитику или привести к неверным действиям (например, дублирующиеся отправки email).

Соответствие требованиям: Удаление данных, которые больше не должны храниться (например, по соображениям конфиденциальности).

Обзор основных методов Google Apps Script для работы с данными

Основным сервисом для работы с Google Sheets является SpreadsheetApp. Ключевые классы и методы включают:

SpreadsheetApp.getActiveSpreadsheet(): Получение активной таблицы.

getSheetByName(name): Получение листа по имени.

getDataRange(): Получение диапазона со всеми данными на листе.

getRange(a1Notation): Получение конкретного диапазона.

getValues(): Получение данных из диапазона в виде двумерного массива.

setValues(values): Запись данных в диапазон.

clearContent(), clearFormat(), clear(): Очистка содержимого, форматирования или всего вместе.

deleteRow(rowPosition), deleteRows(rowPosition, howMany): Удаление строк.

deleteColumn(columnPosition), deleteColumns(columnPosition, howMany): Удаление столбцов.

Проверка данных в Google Sheets с помощью Google Apps Script

Проверка данных перед их использованием или дальнейшей обработкой помогает избежать ошибок и повысить надежность ваших скриптов и отчетов.

Получение данных из Google Sheets

Для проверки данных их сначала необходимо извлечь из таблицы. Наиболее эффективный способ — получить весь диапазон данных в виде массива.

/**
 * Получает все данные с указанного листа.
 * @param {string} sheetName Имя листа.
 * @returns {string[][]} Двумерный массив данных.
 * @throws {Error} Если лист с указанным именем не найден.
 */
function getDataFromSheet(sheetName: string): string[][] {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(sheetName);
  if (!sheet) {
    throw new Error(`Лист с именем "${sheetName}" не найден.`);
  }
  return sheet.getDataRange().getValues();
}

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

Проверки реализуются с использованием стандартных возможностей JavaScript для работы с массивами и строками.

Тип данных: Используйте typeof, instanceof или регулярные выражения.

Допустимые значения: Проверка на вхождение в заранее определенный список или соответствие шаблону.

Диапазоны: Сравнение числовых значений с границами диапазона.

Обработка ошибок при проверке данных

При обнаружении некорректных данных можно:

Логировать ошибку: Записать информацию об ошибке с помощью Logger.log() или в отдельный лог-файл/лист.

Пометить ячейку/строку: Изменить фон ячейки или добавить комментарий.

Пропустить строку: Не обрабатывать строки с ошибками.

Удалить строку: Если данные критически неверны (рассмотрим ниже).

Примеры кода для проверки данных в Google Sheets

Пример проверки URL-адресов в столбце ‘Landing Page’ для списка рекламных объявлений.

/**
 * Проверяет корректность URL в указанном столбце.
 * @param {string} sheetName Имя листа.
 * @param {number} urlColumnIndex Индекс столбца с URL (начиная с 0).
 */
function validateUrls(sheetName: string, urlColumnIndex: number): void {
  const data = getDataFromSheet(sheetName);
  const urlRegex = /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/i;

  // Пропускаем заголовок
  for (let i = 1; i < data.length; i++) {
    const url = data[i][urlColumnIndex];
    if (typeof url !== 'string' || !urlRegex.test(url)) {
      Logger.log(`Некорректный URL в строке ${i + 1}: ${url}`);
      // Опционально: пометить ячейку
      // const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
      // sheet?.getRange(i + 1, urlColumnIndex + 1).setBackground('yellow');
    }
  }
  SpreadsheetApp.flush(); // Применяем изменения (если были, например, setBackground)
}

// Пример вызова
// validateUrls('CampaignData', 3); // Проверить URL в 4-м столбце листа 'CampaignData'

Удаление данных в Google Sheets с помощью Google Apps Script

Удаление ненужных или некорректных данных — частая задача при чистке таблиц.

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

Методы deleteRow(), deleteRows(), deleteColumn(), deleteColumns() позволяют удалять строки/столбцы целиком. Важно помнить, что удаление строк смещает нумерацию последующих строк, поэтому при удалении в цикле лучше итерировать с конца.

Удаление содержимого ячеек

Методы clearContent(), clear() (с опциями) позволяют очистить значения в ячейках, не удаляя сами строки или столбцы.

Удаление дубликатов

Удаление строк-дубликатов часто требуется при работе со списками контактов или логами.

/**
 * Удаляет строки-дубликаты на основе значений в указанном столбце.
 * @param {string} sheetName Имя листа.
 * @param {number} keyColumnIndex Индекс ключевого столбца для проверки дубликатов (начиная с 0).
 */
function removeDuplicateRows(sheetName: string, keyColumnIndex: number): void {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(sheetName);
  if (!sheet) {
    Logger.log(`Лист "${sheetName}" не найден.`);
    return;
  }

  const data = sheet.getDataRange().getValues();
  const uniqueKeys = new Set();
  const rowsToDelete: number[] = [];

  // Начинаем с конца, чтобы индексы удаляемых строк не сбивались
  for (let i = data.length - 1; i >= 0; i--) {
    const key = data[i][keyColumnIndex]?.toString(); // Приводим к строке для универсальности
    if (key === undefined || key === null) continue; // Пропускаем, если ключ пуст

    if (uniqueKeys.has(key)) {
      rowsToDelete.push(i + 1); // Сохраняем номер строки (1-based)
    } else {
      uniqueKeys.add(key);
    }
  }

  // Удаляем строки одним пакетом (эффективнее)
  if (rowsToDelete.length > 0) {
    // Сортируем индексы для корректного удаления пачками, если необходимо (хотя deleteRow работает и так)
    rowsToDelete.sort((a, b) => a - b);
    Logger.log(`Найдено дубликатов для удаления: ${rowsToDelete.length}`);

    // Удаляем по одной строке с конца, чтобы избежать проблем с индексацией
    for (let i = rowsToDelete.length - 1; i >= 0; i--) {
      sheet.deleteRow(rowsToDelete[i]);
    }
    SpreadsheetApp.flush(); // Применяем изменения
  }
}

// Пример вызова
// removeDuplicateRows('Leads', 1); // Удалить дубликаты по 2-му столбцу (Email) на листе 'Leads'
Реклама

Удаление пустых строк

Часто таблицы содержат пустые строки, которые мешают анализу.

/**
 * Удаляет полностью пустые строки с листа.
 * @param {string} sheetName Имя листа.
 */
function deleteEmptyRows(sheetName: string): void {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(sheetName);
  if (!sheet) {
    Logger.log(`Лист "${sheetName}" не найден.`);
    return;
  }
  const maxRows = sheet.getMaxRows();
  const data = sheet.getDataRange().getValues();
  const rowsToDelete: number[] = [];

  // Идем с конца
  for (let i = data.length - 1; i >= 0; i--) {
    // Проверяем, все ли ячейки в строке пустые
    const isEmpty = data[i].every(cell => cell === '');
    if (isEmpty) {
      rowsToDelete.push(i + 1); // Номер строки (1-based)
    }
  }

  if (rowsToDelete.length > 0) {
    Logger.log(`Найдено пустых строк для удаления: ${rowsToDelete.length}`);
    for (let i = 0; i < rowsToDelete.length; i++) {
      // Удаляем строку с учетом ее текущего положения (т.к. предыдущие уже удалены)
      // Если удаляем с конца, индекс всегда корректен
      sheet.deleteRow(rowsToDelete[i]);
    }
    SpreadsheetApp.flush();
  }
}

// Пример вызова
// deleteEmptyRows('ReportData');

Автоматизация процессов проверки и удаления данных

Ручной запуск скриптов не всегда удобен. Google Apps Script позволяет автоматизировать эти процессы.

Триггеры, запускающие проверку и удаление данных

Триггеры по времени (Time-driven): Запускают функцию по расписанию (ежедневно, еженедельно и т.д.). Идеально для регулярной чистки данных.

Триггеры по событию (Event-driven):

onEdit(e): Срабатывает при редактировании любой ячейки. Требует осторожности, чтобы не замедлять работу пользователя. Подходит для простых проверок.

onChange(e): Срабатывает при структурных изменениях (вставка/удаление строк/столбцов, изменения через формы и т.д.). Более мощный, чем onEdit, но также требует оптимизации.

onFormSubmit(e): Срабатывает при отправке Google Формы, связанной с таблицей. Отлично подходит для валидации данных, поступающих из форм.

Настройка триггеров производится в редакторе скриптов (раздел "Триггеры").

Создание пользовательских функций для повторного использования

Выносите логику проверки и удаления в отдельные, хорошо документированные функции. Это позволяет легко вызывать их из разных триггеров или других скриптов, а также упрощает тестирование и поддержку.

Логирование и отслеживание результатов проверки и удаления

Используйте Logger.log() для отладки и console.log() для просмотра логов в Stackdriver Logging (более продвинутый вариант). Для постоянного мониторинга можно записывать результаты операций (сколько строк удалено, какие ошибки найдены) на отдельный лист в таблице.

Практические примеры и советы

Пример 1: Проверка формата email-адресов и удаление некорректных

Комбинация проверки и удаления: находим строки с невалидными email и сразу удаляем их.

/**
 * Проверяет email в указанном столбце и удаляет строки с некорректными адресами.
 * @param {string} sheetName Имя листа.
 * @param {number} emailColumnIndex Индекс столбца с email (начиная с 0).
 */
function validateAndRemoveInvalidEmails(sheetName: string, emailColumnIndex: number): void {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(sheetName);
  if (!sheet) {
    Logger.log(`Лист "${sheetName}" не найден.`);
    return;
  }

  const data = sheet.getDataRange().getValues();
  const emailRegex = /^[^
\s@]+@[^
\s@]+\.[^
\s@]+$/i;
  const rowsToDelete: number[] = [];

  // Идем с конца (пропускаем заголовок, если он есть - i > 0)
  for (let i = data.length - 1; i > 0; i--) {
    const email = data[i][emailColumnIndex];
    // Считаем строку некорректной, если email не строка или не соответствует формату
    if (typeof email !== 'string' || !emailRegex.test(email)) {
      Logger.log(`Обнаружен некорректный email в строке ${i + 1}: "${email}". Строка будет удалена.`);
      rowsToDelete.push(i + 1);
    }
  }

  if (rowsToDelete.length > 0) {
    Logger.log(`Удаление ${rowsToDelete.length} строк с некорректными email.`);
    // Удаляем по одной строке с конца
    for (const rowIndex of rowsToDelete) {
      sheet.deleteRow(rowIndex);
    }
    SpreadsheetApp.flush();
  }
}

// Пример вызова
// validateAndRemoveInvalidEmails('Subscribers', 2); // Проверить и удалить из 3-го столбца

Пример 2: Удаление строк, где определенная ячейка пуста

Удаление строк на основе пустого значения в критически важном столбце (например, ‘ID Транзакции’ или ‘Источник трафика’).

/**
 * Удаляет строки, в которых ячейка в указанном столбце пуста.
 * @param {string} sheetName Имя листа.
 * @param {number} checkColumnIndex Индекс проверяемого столбца (начиная с 0).
 */
function deleteRowsWithEmptyCell(sheetName: string, checkColumnIndex: number): void {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(sheetName);
  if (!sheet) {
    Logger.log(`Лист "${sheetName}" не найден.`);
    return;
  }

  const data = sheet.getDataRange().getValues();
  const rowsToDelete: number[] = [];

  // Идем с конца (пропускаем заголовок, если нужно)
  for (let i = data.length - 1; i >= 1; i--) { // i >= 1 чтобы пропустить заголовок
    const cellValue = data[i][checkColumnIndex];
    if (cellValue === null || cellValue === undefined || cellValue === '') {
      rowsToDelete.push(i + 1);
    }
  }

  if (rowsToDelete.length > 0) {
    Logger.log(`Удаление ${rowsToDelete.length} строк с пустым значением в столбце ${checkColumnIndex + 1}.`);
    for (const rowIndex of rowsToDelete) {
      sheet.deleteRow(rowIndex);
    }
    SpreadsheetApp.flush();
  }
}

// Пример вызова
// deleteRowsWithEmptyCell('Transactions', 0); // Удалить строки, где первый столбец (ID) пуст

Советы по оптимизации кода для повышения производительности

Минимизируйте вызовы SpreadsheetApp: Читайте и записывайте данные большими блоками (getValues(), setValues()), а не по ячейкам в цикле.

Используйте deleteRows() вместо deleteRow() в цикле: Хотя примеры выше используют deleteRow() для простоты при итерации с конца, для больших объемов данных эффективнее собрать индексы всех удаляемых строк и использовать deleteRows() (требует более сложной логики управления индексами при удалении нескольких диапазонов).

Итерация с конца при удалении: При использовании deleteRow() в цикле всегда идите с конца массива/таблицы, чтобы избежать проблем со смещением индексов.

Используйте Set для быстрой проверки уникальности: Как в примере removeDuplicateRows, Set обеспечивает O(1) среднюю сложность для проверки наличия элемента.

Применяйте SpreadsheetApp.flush(): Используйте после серии операций записи или удаления, чтобы применить изменения немедленно, если это требуется для дальнейшей логики, но избегайте его вызова внутри циклов.

Учитывайте ограничения Google Apps Script: Помните о лимитах на время выполнения скриптов (6 минут для обычных аккаунтов, 30 минут для Workspace) и другие квоты.


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