Все публично торгуемые компании и отдельные лица используют EDGAR — электронную систему сбора, анализа и поиска данных — для подачи необходимых, срочных документов в Комиссию по ценным бумагам и биржам США.
Система Edgar предоставляет доступный веб-интерфейс, который позволяет любому искать эти документы. Для тех, кто, возможно, не знает, что именно ищет, или заинтересован в самостоятельном изучении данных; SEC предоставляет ежедневные индексы данных, доступных для скачивания.
Вот как я проанализировал текстовое содержимое индексных файлов сканера. В файле crawler.20210122.idx файлы edgar представлены в виде строк текста с такой схемой:
Я провел несколько выборочных проверок и визуально проверил данные. Поля записи кажутся разделенными пробелами. Я предполагал, что значения полей не будут содержать последовательные пробелы и что пробел между значениями полей будет содержать не менее 2 последовательных пробелов. Это показалось мне разумным предположением, поскольку это упростило бы код для анализа этих записей.
В моем конвейере данных мне нужна была функция, которая брала бы строку текста, представляющую запись, и возвращала бы список значений записи.
Функция должна как минимум пройти следующий тест:
Мой первый подход выглядел так:
«Как изящно и просто!» — подумал я, чувствуя гордость за себя. Я разделяю строку вокруг разделителя, обрезаю все начальные и конечные пробелы, а затем отфильтровываю все пустые строки.
К моему большому огорчению, мои предположения оказались неверными…
Просматривая данные регистрации, моя программа сломалась на человеке, у которого были последовательные пробелы между его фамилией и именем. ☹️
Функция также должна пройти этот тест:
Еще больше усложняет ситуацию то, что названия компаний могут вообще не содержать пробелов. Типы форм также могут содержать пробелы! Эта схема довольно дикая и грязная, мне это не нравится, но я могу с этим смириться.
Нам нужно будет написать более надежную функцию синтаксического анализа для обработки этих дополнительных случаев:
Я немного подумал об этом и придумал алгоритм, который проходит все тесты, но…
Мой красивый элегантный код, кажется, превратился в чудовище! ?
Общая идея алгоритма состоит в том, чтобы пройти по строке в обратном порядке (от конца к началу), идентифицировать значения и создать их список за один проход.
Давайте посмотрим глубже, чтобы понять, что здесь происходит.
Я использую функцию Enum.reduce
для перебора индексов строки и отслеживания своего состояния. В моем состоянии я слежу за тремя вещами:
- Список значений, которые я извлек на данный момент.
- Индекс того, где в общей строке заканчивается текущее значение.
- Логическое значение, определяющее, является ли текущий индекс частью значения или нет.
Далее, в моей вызванной функции у меня есть 5 условий, которые я обрабатываю:
- Я уже извлек все 5 значений, ничего не делать.
- Текущий индекс не находится в значении, и я смотрю на что-то, что не является пробелом… должно быть, это конец значения! Я переворачиваю логическое значение и отмечаю конец значения.
- Текущий индекс — это значение, и если я уже нашел 4 других значения и не смотрю на пробел… это должно быть окончание названия компании! Извлеките имя и добавьте его в наш список значений.
- Текущий индекс — это значение, и я смотрю на пробел, и следующий символ — тоже пробел… это должно быть начало значения! Извлеките значение, добавьте его в наш список и укажите, что мы больше не находимся в значении.
- Ни одно из приведенных выше условий не было выполнено, ничего не делайте.
В конце концов, я просто возвращаю значения, извлеченные во время редукции.
Есть вопросы или лучший алгоритм? Дай мне знать в комментариях!