Аналоги в Python и JavaScript. Часть вторая

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


Сегодня поговорим о сериализации словарей, JSON, регулярках, об ошибках и исключениях.


Другие статьи в этой серии:


  1. Первая часть — приведение к типу, тернарный оператор, доступ к свойству по имени свойства, словари, списки, строки, конкатенация строк.
  2. Эта статья
  3. Часть третья: современные Python и JS: строковые шаблоны (f-строки), распаковка списков, лямбда-функции, итерации по спискам, генераторы, множества.
  4. Четвертая часть — аргументы функций, создание и работа с классами, наследование, геттеры-сеттеры и свойства класса.

JSON


При работе со многими API удобно сериализовать объекты в JSON-объекты для удобства передачи и последующего разбора.


В Питоне есть стандартный модуль json:


import json
json_data = json.dumps(dictionary, indent=4)
dictionary = json.loads(json_data)

Здесь мы форматируем JSON с помощью отступов в 4 пробела.


В JS существует объект JSON с методами для создания и парсинга JSON-строк:


json_data = JSON.stringify(dictionary, null, 4);
dictionary = JSON.parse(json_data);

Разбираем строки регулярками


В прошлой статье мы соединяли несколько строк в одну. Но как разделить одну длинную строку на несколько, особенно если разделителем выступает не один символ типа запятой, а целый диапазон различных вариантов? Здесь нам на помощь приходят регулярные выражения и метод split().


В Питоне метод split() относится к шаблону регулярных выражений. Вот как можно разделить текстовую строку на предложения по знакам препинания:


import re

# Один или более символов "!?." за которыми следует ноль или более пробельных символов
delimiter = re.compile(r'[!?\.]+\s*')

text = "Hello!!! What's new? Follow me."
sentences = delimiter.split(text)
# sentences == ['Hello', "What's new", 'Follow me', '']

В JS метод split() относится к строкам:


// Один или более символов "!?." за которыми следует ноль или более пробельных символов
delimiter = /[!?\.]+\s*/;

text = "Hello!!! What's new? Follow me.";
sentences = text.split(delimiter)
// sentences === ["Hello", "What's new", "Follow me", ""]

Поиск регулярками по шаблону


Регулярные выражения часто используются для валидации данных из форм.
К примеру, для проверки корректности веденного e-mail адреса его надо сопоставить с шаблоном регулярного выражения.


Автор перевода в курсе

что проверка адреса регулярками задача нетривиальная и несколько сложнее приведенного в этой статье метода


В Питоне это будет выглядеть примерно так:


import re

# name, "@", and domain
pattern = re.compile(r'([\w.+\-]+)@([\w\-]+\.[\w\-.]+)')

match = pattern.match('hi@example.com')
# match.group(0) == 'hi@example.com'
# match.group(1) == 'hi'
# match.group(2) == 'example.com'

Если участок текста совпадает с шаблоном, то при помощи метода group() возвращается совпавший участок целиком в котором можно выделить отдельные группы определенные в шаблоне.


0 — совпавшая (под)строка целиком, 1 — первая группа, 2 — вторая и т.д.


Если совпадений не найдено, вернется объект типа None.


В JS существует строковый метод match()который возвращает либо совпавший участок строки либо null.


// name, "@", and domain
pattern = /([\w.+\-]+)@([\w\-]+\.[\w\-.]+)/;

match = 'hi@example.com'.match(pattern);
// match[0] === 'hi@example.com'
// match[1] === 'hi'
// match[2] === 'example.com'

В JS совпавший объект выглядит как массив. Элемент с индексом [0] — совпавшая (под)строка целиком, 1-й элемент — первая группа, 2-й — вторая и т.д. — все в соответствии с группами определенными в шаблоне.


Иногда кроме поиска требуется определить положение образца в тексте. Это можно сделать с помощью метода search().
В Питоне этот метод относится к регулярным выражениям и возвращает совпавший объект. У этого совпавшего объекта есть метод start(), возвращающий начало вхождения этой подстроки в основную строку:


text = 'Say hi at hi@example.com'
first_match = pattern.search(text)
if first_match:
    start = first_match.start()  # start == 10

В JS метод есть строковый метод search() возвращающий индекс начала подстроки. Или -1 если совпадений не было найдено.



text = 'Say hi at hi@example.com';
first_match = text.search(pattern);
if (first_match > -1) {
    start = first_match;  // start === 10
}

Замена по шаблону с помощью регулярных выражений


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


В Питоне для этого есть метод шаблона регулярных выражений sub():



html = pattern.sub(
    r'<a href="mailto:\g<0>">\g<0></a>',
    'Say hi at hi@example.com',
)
# html == 'Say hi at <a href="mailto:hi@example.com">hi@example.com</a>'

Разработчики на JS могут использовать строковый метод replace():


html = 'Say hi at hi@example.com'.replace(
    pattern, 
    '<a href="mailto:$&">$&</a>',
);
// html === 'Say hi at <a href="mailto:hi@example.com">hi@example.com</a>'

В Питоне совпавшие группы доступны как \g<0>, \g<1>, \g<2> и т.д.
В JS аналогично $&, $1, $2 и т.д.


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


Давайте изменим все встречающиеся e-mail адреса ПРОПИСНЫМИ БУКВАМИ.


В Питоне функция замены получает совпавший объект. Мы используем метод group() чтобы произвести действия с совпавшим текстом и вернуть его в виде замены:


text = pattern.sub(
    lambda match: match.group(0).upper(), 
    'Say hi at hi@example.com',
)
# text == 'Say hi at HI@EXAMPLE.COM'

В JS функция замены получает совпавшую строку целиком, первое вхождение, второе и т.д. Мы производим необходимые действия и возвращаем измененную строку:


text = 'Say hi at hi@example.com'.replace(
    pattern,
    function(match, p1, p2) {
        return match.toUpperCase();
    }
);
// text === 'Say hi at HI@EXAMPLE.COM'

Обработка ошибок


В противоположность Питону фронтенд-браузерный JavaScript обычно не используют для записи-чтения файлов или доступа к базам данных. Поэтому блоки try..catch довольно редко встречаются в JS по сравнению с блоками try..except в Питоне.


Но, в любом случае, обработка ошибок может быть произведена в пользовательском скрипте, вызвана из библиотечной функции и перехвачена в основном коде.


В следующем примере на Пионе мы определим свое исключение MyException, порождаем его в функции, и посмотрим как его перехватить и обработать в блоке try..except..finally:


class MyException(Exception):
    def __init__(self, message):
        self.message = message

    def __str__(self):
        return self.message

def proceed():
    raise MyException('Error happened!')

try:
    proceed()
except MyException as err:
    print('Sorry! {}'.format(err))
finally:
    print('Finishing')    

Следующий код на JS делает то же самое — мы определяем класс MyException, порождаем его в функции, перехватываем и обрабатываем в блоке try..catch..finally:


function MyException(message) {
   this.message = message;
   this.toString = function() {
       return this.message;
   }
}

function proceed() {
    throw new MyException('Error happened!');
}

try {
    proceed();
} catch (err) {
    if (err instanceof MyException) {
        console.log('Sorry! ' + err);
    }
} finally {
    console.log('Finishing');
}

В обоих языках класс MyException имеет параметр message и метод для строкового представления в зависимости от значения message.


Конечно, исключения должны вызваться/порождаться только в случае ошибки. И если вы определили эту ошибку в своем модуле.


Выводы


  • Сериализация в/из JSON достаточно прямолинейна — что в Питоне что в JS.
  • Регулярки — мощный инструмент обработки текстов в обоих языках.
  • Можно производить замены с помощью функций.
  • Для более сложных случаев можно использовать вызов, перехват и обработку ошибок.

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


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

Поделиться публикацией
Ой, у вас баннер убежал!

Ну. И что?
Реклама
Комментарии 2
    0
    [!?\.]+\s*

    Один или более символов "!?." следующих за пробелом

    Нет, это один или более символов "!?.", за которыми следует ноль или более whitespace-символов.

      +1
      Спасибо, поправил

    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

    Самое читаемое