Писать код не сложно. Сложно писать код так, чтобы его было легко читать и поддерживать. К сожалению, не всегда понятно, как лучше организовать код. Бывает, что при чтении кода спотыкаешься и долго не можешь понять, что же здесь не так. Продолжить чтение →
Категория / Программирование
Технологии работы с информацией. Реляционные базы данных, примеры работы с SQL. Парсинг, дата майнинг, извлечение знаний.
Как расшифровать текст с кракозябрами вместо русских букв
Время от времени приходится сталкиваться с текстом в непонятной кодировке, типа такого:
Ëþäè â Ãðîóâëåíäå, ìàëåíüêîì (ïî ìåðêàì Êàëèôîðíèè) ãîðîäêå â øåñòüñîò æèòåëåé, âûõîäèëè íà óëèöû, ñòîÿëè ïåðåä ñâîèìè äîìàìè ñ öâåòàìè íà ïîäîêîííèêàõ è ñìîòðåëè, êàê ýòîò ïèðîêóìóëþñ âûðàñòàåò âûøå Ñüåððû-Íåâàäû. ß è ñàìà ñòîÿëà òàì â áëàãîãîâåíèè è óæàñå è ïîíèìàëà áåç âñÿêèõ ñëîâ, ÷òî åñëè íå ïîéäåò äîæäü, òî ñëåäóþùèå ïîæàðû áóäóò åù¸ óæàñíåå, à åñëè äîæäè âñ¸ æå ïîéäóò è îêàæóòñÿ ñëèøêîì îáèëüíûìè, òî ýòî ñîææ¸ííûå ãîðíûå ñêëîíû ñìîåò íàâîäíåíèÿìè. Âñ¸ áûëî áóêâàëüíî íà ãðàíè êàòàñòðîôû. Íî ðÿäîì áûëè öâåòû â ãîðøêàõ, è íåîáîææ¸ííûå ñîñíû, è òðóùèåñÿ î íîãè ñîáàêè, è ðåñòîðàí, îòêðûòûé äëÿ óæèíà; è ÷óâñòâîâàëîñü, ÷òî âñå íà óëèöå âçäûõàþò ñ áëàãîäàðíîñòüþ çà òî, ÷òî âñ¸ ýòî ó íèõ åù¸ åñòü. Õîòÿ áû íåíàäîëãî (Äèàíà Ìàðêóì, Äåñÿòûé îñòðîâ).
Если текст маленький, то поможет онлайн-декодер, а если текст большой — поможет текстовый редактор. Я использую Sublime Text, подозреваю что этот трюк возможен и в других текстовых редакторах, которые умеют работать с разными кодировками.
В любом случае, начните с онлайн-декодера, чтобы понять с какими кодировками нужно работать. Раскодируйте фрагмент текста и запомните направление декодирования (в нашем случае: ISO-8859-1 → Windows-1251):
Вся дальнейшая работа будет проходить в текстовом редакторе.
Шаг 1. Создайте обычный пустой текстовый файл, сохраните его с кодировкой Western (ISO 8859-1):
Шаг 2. Скопируйте текст с кракозябрами и вставьте его в созданный файл:
Шаг 3. Сохраните файл (Ctrl + S).
Шаг 4. Откройте файл с кодировкой Cyrillic (Windows 1251):
Шаг 5. Наслаждайтесь результатом:
MongoDB: The ‘cursor’ option is required
При использовании агрегации через устаревший драйвер MongoDB без указания опций возникает ошибка
Throwable; type: [MongoResultException]; code: [9]; message: [localhost:27017: The ‘cursor’ option is required, except for aggregate with the explain argument]; err level: [1 (E_ERROR)]
Внятного описания в документации, что именно должно быть передано в параметре cursor, нет. Так как драйвер ждёт объект, избавиться от ошибки можно, передав в параметрах метода aggregate() в опции cursor пустой объект:
$pipeline = array(array( '$group' => array( '_id' => null, 'min' => array('$min' => '$update_time'), 'max' => array('$max' => '$update_time'), ), )); $options = array('cursor' => new stdClass()); $res = $MongoCollection->aggregate($pipeline, $options);
Пример выше показывает, как выбрать из коллекции минимальную и максимальную запись.
MongoDB: как разделить поле _id после группировки
Группировку данных в MongoDB можно делать как по одному полю, так и по нескольким, превращая их во вложенный документ:
db.my_collection.aggregate([ {$group: { _id: {surname: "$surname", name: "$name"} }}, ]);
Этот запрос вернёт такой результат:
{_id: {name: "Аттикус", surname: "Финч"}} {_id: {name: "Индиана", surname: "Джонс"}} {_id: {name: "Джеймс", surname: "Бонд"}} {_id: {name: "Рик", surname: "Блейн"}} {_id: {name: "Уилл", surname: "Кейн"}}
А вложенные документы поднять на уровень выше, нужна проекция:
db.my_collection.aggregate([ {$group: { _id: {surname: "$surname", name: "$name"} }}, {$project: {_id: 0, surname: "$_id.surname", name: "$_id.name"}}, {$sort: {surname: 1, name: 1}} ]);
Этот запрос вернёт данные в таком виде:
{name: "Рик", surname: "Блейн"} {name: "Джеймс", surname: "Бонд"} {name: "Индиана", surname: "Джонс"} {name: "Уилл", surname: "Кейн"} {name: "Аттикус", surname: "Финч"}
PHP: Detected an illegal character in input string
При преобразовании строки в требуемую кодировку к кодировке, требуемой на выходе можно добавить параметр TRANSLIT или IGNORE. Первый включает режим транслитерации и заменяет проблемный символ на один или несколько наиболее близких по внешнему виду. Ключевое слово — заменяет. Возможно, наиболее близким символом будет знак вопроса, но тем не менее. Второй параметр удаляет те символы, которые не могут быть представлены в требуемой кодировке.
В комментариях к документации один из пользователей упомянул про символ, который не получается проигнорировать — на нём даже с параметром IGNORE iconv падает с ошибкой «Detected an illegal character in input string». И поэтому появилась рекомендация использовать одновременно два параметра: //TRANSLIT//IGNORE — типа, игнорировать всё, что не удалось транслитерировать. Однако, повторюсь, параметр TRANSLIT заменяет все проблемные символы, после него уже нечего игнорировать. В итоге получаем такую картину:
// работает iconv('utf-8', 'windows-1251//TRANSLIT', '∙'); iconv('utf-8', 'windows-1251//TRANSLIT//IGNORE', '∙'); // падает с ошибкой Detected an illegal character in input string iconv('utf-8', 'windows-1251//IGNORE', '∙'); iconv('utf-8', 'windows-1251//IGNORE//TRANSLIT', '∙');
В итоге имеем бессмысленные комбинации //TRANSLIT//IGNORE и //IGNORE//TRANSLIT, которые встречаются в ответах на SO.
Python: проверка на прерывание цикла
В Python у циклов while и for есть опциональный блок else, который проверяет, выполнился ли цикл полностью. Если ключевое слово break не было вызвано, будет выполнен блок else.
while… else:
numbers = [1, 3, 5] position = 0 while position < len(numbers): number = numbers[position] if number % 2 == 0: print('Найдено четное число', number) break position += 1 else: print('Четное число не найдено')
for… else:
numbers = [1, 3, 5] for number in numbers: if number % 2 == 0: print('Найдено четное число', number) break else: print('Четное число не найдено')
Подобная конструкция позволяет выполнить некоторое действие при полном завершении работы с циклом (вывод сообщения здесь — явный флаг штатного завершения обхода цикла):
for name in ['Алиса', 'Боб']: print(name) else: print('Обход цикла завершен')
Предел прочности
Прекрасное о Дамбе Баньцяо в Википедии:
Дамба была сконструирована таким образом, чтобы пережить крупнейшие наводнения, которые случаются раз в тысячу лет (306 мм осадков за день). Однако в августе 1975 года произошло крупнейшее за 2000 лет наводнение…
Когда делаешь код-ревью своего же кода
Начало: 5:24
PHP: Проверка строк, содержащих числа
Если на входе есть строка, которая может содержать целое число или число с плавающей точкой и нужно эту строку привести к нужному состоянию, то можно сделать так:
if (is_numeric($string)) { if ((int)$string == $string) { $string = (int)$string; } else { $string = (float)$string; } }
Функция is_numeric проверяет, является ли переменная числом или строкой, содержащей число (ни is_int, ни is_float не делают вторую часть проверки и при получении строки на входе возвращают false). Далее приводим строку к целому числу и делаем нестрогое сравнение, чтобы убедиться, что перед нами действительно целое число.
Стили написания составных слов
- kebab-case (lisp-case) — шашлычный-регистр, позвоночный-регистр
- snake_case — змеиный_регистр
- SCREAMING_SNAKE_CASE
- Train-Case
- CamelCase (UpperCamelCase, PascalCase) — ВерблюжийРегистр, ГорбатыйРегистр, СтильВерблюда
- lowerCamelCase