Валидация координат

Координаты в геопространственных системах представляются в нескольких распространённых форматах, каждый из которых требует отдельного подхода к валидации.

Основные варианты:

  • Десятичные градусы: 55.7558, 37.6173
  • Объектная форма: { lat: 55.7558, lng: 37.6173 }
  • Строковый формат с разделителями: "55.7558,37.6173"
  • Градусы/минуты/секунды (DMS): "55°45'20.8\"N 37°37'02.3\"E"

При работе с JavaScript-библиотекой Validator.js важно учитывать, что она не предоставляет специализированного высокоуровневого валидатора координат как единый стандартный метод. Вместо этого используется комбинация базовых проверок и пользовательских правил.


Диапазоны значений и базовые ограничения

Любая система валидации координат опирается на строгие числовые границы:

  • Широта (latitude): от -90 до 90
  • Долгота (longitude): от -180 до 180

Эти ограничения являются фундаментальными и не зависят от формата входных данных.

Ключевая логика валидации заключается не только в проверке числа, но и в контроле диапазона после приведения значения к числовому типу.


Использование Validator.js для числовой валидации

Библиотека Validator.js предоставляет набор универсальных методов, которые применяются как строительные блоки:

  • isFloat(value) — проверка, является ли значение числом с плавающей точкой
  • isDecimal(value) — проверка десятичного формата
  • toFloat(value) — приведение строки к числу
  • trim(value) — удаление лишних пробелов
  • matches(value, pattern) — проверка по регулярному выражению

Эти методы не предназначены специально для геокоординат, но позволяют построить строгую систему проверки.


Валидация широты и долготы по отдельности

Разделение координат на две сущности упрощает контроль корректности.

const validator = require('validator');

function isValidLatitude(lat) {
  if (!validator.isFloat(String(lat))) return false;

  const value = validator.toFloat(String(lat));
  return value >= -90 && value <= 90;
}

function isValidLongitude(lng) {
  if (!validator.isFloat(String(lng))) return false;

  const value = validator.toFloat(String(lng));
  return value >= -180 && value <= 180;
}

Ключевой момент: проверка диапазона всегда выполняется после приведения к числу, так как строковые значения могут содержать скрытые символы или пробелы.


Валидация пары координат (lat, lng)

Часто координаты передаются в виде строки или массива. В этом случае требуется комплексная проверка структуры.

function isValidLatLngString(input) {
  if (!validator.isString(input)) return false;

  const parts = input.split(',');

  if (parts.length !== 2) return false;

  const lat = validator.trim(parts[0]);
  const lng = validator.trim(parts[1]);

  return isValidLatitude(lat) && isValidLongitude(lng);
}

Валидация объектного формата

При работе с API распространён формат JSON-объектов:

function isValidLatLngObject(obj) {
  if (typeof obj !== 'object' || obj === null) return false;

  const hasLat = Object.prototype.hasOwnProperty.call(obj, 'lat');
  const hasLng = Object.prototype.hasOwnProperty.call(obj, 'lng');

  if (!hasLat || !hasLng) return false;

  return isValidLatitude(obj.lat) && isValidLongitude(obj.lng);
}

Такой подход снижает риск ошибок, связанных с неверным порядком координат.


Регулярные выражения для строгого контроля формата

Validator.js позволяет использовать метод matches, что удобно для первичной фильтрации входных данных.

Десятичные координаты

const pattern = /^-?\d+(\.\d+)?$/;

function isStrictDecimal(value) {
  return validator.matches(String(value), pattern);
}

Однако важно учитывать, что регулярное выражение не заменяет числовую проверку диапазона.


DMS формат (градусы, минуты, секунды)

Формат DMS требует отдельной логики, поскольку включает символы и направления.

Пример базовой проверки структуры:

const dmsPattern = /^[0-9]{1,3}°\s?[0-9]{1,2}'\s?[0-9]{1,2}(\.[0-9]+)?"?[NS]\s+[0-9]{1,3}°\s?[0-9]{1,2}'\s?[0-9]{1,2}(\.[0-9]+)?"?[EW]$/;

function isValidDMS(value) {
  return validator.matches(value, dmsPattern);
}

В реальных системах DMS обычно конвертируется в десятичные координаты перед дальнейшей обработкой.


Нормализация данных перед валидацией

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

  • удаление пробелов
  • замена запятой на точку
  • приведение к строковому типу
  • устранение нестандартных символов
function normalizeCoordinate(value) {
  return String(value)
    .replace(',', '.')
    .trim();
}

Отсутствие нормализации приводит к ложным отрицаниям при валидации.


Проблемы точности чисел с плавающей точкой

JavaScript использует IEEE 754, что приводит к погрешностям:

  • 0.1 + 0.2 !== 0.3

Для координат это критично при сравнении и хранении.

Практический подход:

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

Локализация числовых форматов

В некоторых регионах используется запятая как десятичный разделитель:

  • "55,7558" вместо "55.7558"

Validator.js не учитывает это автоматически, поэтому требуется предобработка:

function normalizeDecimalLocale(value) {
  return String(value).replace(',', '.');
}

Потенциальные ошибки при валидации координат

1. Строки с лишними символами

Пример: " 55.7558N "

Без строгой очистки такие значения могут пройти частичную проверку.

2. Частично валидные числа

Пример: "90.0000001" формально число, но выходит за пределы допустимой широты.

3. Перепутанные значения

Пример: "37.6173, 55.7558" — валидно синтаксически, но логически неверно для некоторых контекстов.


Комплексная функция валидации координат

Объединение всех проверок позволяет построить устойчивый валидатор:

function validateCoordinates(input) {
  if (!input) return false;

  let lat, lng;

  if (typeof input === 'string') {
    const parts = input.split(',');
    if (parts.length !== 2) return false;

    lat = normalizeCoordinate(parts[0]);
    lng = normalizeCoordinate(parts[1]);
  } else if (typeof input === 'object') {
    lat = input.lat;
    lng = input.lng;
  } else {
    return false;
  }

  if (!validator.isFloat(String(lat)) || !validator.isFloat(String(lng))) {
    return false;
  }

  const latNum = validator.toFloat(String(lat));
  const lngNum = validator.toFloat(String(lng));

  return (
    latNum >= -90 &&
    latNum <= 90 &&
    lngNum >= -180 &&
    lngNum <= 180
  );
}

Безопасность и защита от некорректных входных данных

Валидация координат часто используется в публичных API, где возможны попытки:

  • внедрения скриптов через строковые поля
  • передачи некорректных символов Unicode
  • перегрузки системы длинными строками

Validator.js помогает отфильтровать часть таких случаев, но основная защита достигается через:

  • строгую типизацию входных данных
  • ограничение длины строки
  • предварительную очистку

Производственные особенности использования Validator.js

При высоконагруженных системах важно учитывать:

  • регулярные выражения дешевле, чем сложные преобразования
  • многократный вызов toFloat следует минимизировать
  • нормализацию лучше выполнять один раз на входе

Оптимальная архитектура разделяет этапы:

  1. очистка данных
  2. синтаксическая проверка
  3. числовая проверка
  4. проверка диапазонов
  5. бизнес-логика координатной системы