У меня есть серия экспортированных файлов JSON истории местоположений Google гигантский (40-80 МБ), с помощью которых мне было поручено проанализировать выбранные данные об активности. К сожалению, у Google нет параметра или опции в их скачать сайт, чтобы выбрать что-либо, кроме "один гигантский JSON, содержащий навсегда ". (Вариант KML вдвое больше).
Очевидные варианты, такие как JSON-Converter (тестовая версия VBA-JSON); построчный синтаксический анализ с помощью VBA; даже Блокнот ++. Все они разрушить и сжечь. Думаю, ответом может быть RegEx.
Этот скрипт Python может извлечь отметку времени и местоположение из файла размером 40 МБ за две секунды (с помощью RegEx?). Как Python делает это так быстро? (Было бы так же быстро в VBA?)
Я бы смог извлечь все, что мне нужно, по частям, если бы у меня был волшебный кусок RegEx, возможно, с такой логикой:
Удалить всеКроме:
Когда timestampMs и WALKING появляются между * одним и тем же набором [квадратных скобках]:
timestampMS, а также,WALKING.Если проще включить немного больше данных, таких как «все отметки времени» или «Действия все», я мог бы легко просмотреть их позже. Цель состоит в том, чтобы сделать файл маленьким достаточно, чтобы я мог манипулировать им без необходимости арендовать суперкомпьютер, лол.
I tried adapting existing RegEx's but I have a serious issue with both RegEx and musical instruments: doesn't how hard I try, I just can't wrap my head around it. So, this is indeed a "please write code for me" question, but it's just one expression, and I'll pay it forward by writing code for others today! Thanks... ☺ .
}, {
"timestampMs" : "1515564666086", ◁― (Don't need this but it won't hurt)
"latitudeE7" : -6857630899,
"longitudeE7" : -1779694452999,
"activity" : [ {
"timestampMs" : "1515564665992", ◁― EXAMPLE: I want only this, and...
"activity" : [ {
"type" : "STILL",
"confidence" : 65
}, { ↓
"type" : "TILTING",
"confidence" : 4
}, {
"type" : "IN_RAIL_VEHICLE",
"confidence" : 20 ↓
}, {
"type" : "IN_ROAD_VEHICLE",
"confidence" : 5
}, {
"type" : "ON_FOOT", ↓
"confidence" : 3
}, {
"type" : "UNKNOWN",
"confidence" : 3
}, {
"type" : "WALKING", ◁―┬━━ ...AND, I also want this.
"confidence" : 3 ◁―┘
} ]
} ]
}, {
"timestampMs" : "1515564662594", ◁― (Don't need this but it won't hurt)
"latitudeE7" : -6857630899,
"longitudeE7" : -1779694452999,
"altitude" : 42
}, {
Для тестирования я сделал образец файла, представляющий оригинал (за исключением размера). Необработанный JSON может быть загружен непосредственно из эта ссылка Pastebin, или же загружен как локальная копия с эта ссылка TinyUpload, или же, скопированным как «одна длинная строка» ниже:
{"locations" : [ {"timestampMs" : "1515565441334","latitudeE7" : 123456789,"longitudeE7" : -123456789,"accuracy" : 2299}, {"timestampMs" : "1515565288606","latitudeE7" : 123456789,"longitudeE7" : -123456789,"accuracy" : 12,"velocity" : 0,"heading" : 350,"altitude" : 42,"activity" : [ {"timestampMs" : "1515565288515","activity" : [ {"type" : "STILL","confidence" : 98}, {"type" : "ON_FOOT","confidence" : 1}, {"type" : "UNKNOWN","confidence" : 1}, {"type" : "WALKING","confidence" : 1} ]} ]}, {"timestampMs" : "1515565285131","latitudeE7" : 123456789,"longitudeE7" : -123456789,"accuracy" : 12,"velocity" : 0,"heading" : 350,"altitude" : 42}, {"timestampMs" : "1513511490011","latitudeE7" : 123456789,"longitudeE7" : -123456789,"accuracy" : 25,"altitude" : -9,"verticalAccuracy" : 2}, {"timestampMs" : "1513511369962","latitudeE7" : 123456789,"longitudeE7" : -123456789,"accuracy" : 25,"altitude" : -9,"verticalAccuracy" : 2}, {"timestampMs" : "1513511179720","latitudeE7" : 123456789,"longitudeE7" : -123456789,"accuracy" : 16,"altitude" : -12,"verticalAccuracy" : 2}, {"timestampMs" : "1513511059677","latitudeE7" : 123456789,"longitudeE7" : -123456789,"accuracy" : 16,"altitude" : -12,"verticalAccuracy" : 2}, {"timestampMs" : "1513510928842","latitudeE7" : 123456789,"longitudeE7" : -123456789,"accuracy" : 16,"altitude" : -12,"verticalAccuracy" : 2,"activity" : [ {"timestampMs" : "1513510942911","activity" : [ {"type" : "STILL","confidence" : 100} ]} ]}, {"timestampMs" : "1513510913776","latitudeE7" : 123456789,"longitudeE7" : -123456789,"accuracy" : 15,"altitude" : -11,"verticalAccuracy" : 2,"activity" : [ {"timestampMs" : "1513507320258","activity" : [ {"type" : "TILTING","confidence" : 100} ]} ]}, {"timestampMs" : "1513510898735","latitudeE7" : 123456789,"longitudeE7" : -123456789,"accuracy" : 16,"altitude" : -12,"verticalAccuracy" : 2}, {"timestampMs" : "1513510874140","latitudeE7" : 123456789,"longitudeE7" : -123456789,"accuracy" : 19,"altitude" : -12,"verticalAccuracy" : 2,"activity" : [ {"timestampMs" : "1513510874245","activity" : [ {"type" : "STILL","confidence" : 100} ]} ]} ]}
Файл протестирован как действительный с JSONLint и FreeFormatter.
@ WiktorStribiżew - Речь идет о 80 мегах, как в almsot 0.1gb, верно? А функция «заменить все»? Последним примером была замена всех , \n на ,\n\r на двух разных ноутбуках (Win7, Win10, оба 64-битные), N ++ зависает. Я подождал 10 минут и сдался.) Большие файлы открыто ладно, я просто не могу запустить такую огромную операцию. Это то, что вы называете «главной проблемой»? Этот конкретный набор файлов является одноразовой задачей, но я могу придумать много способов адаптировать такой RegEx к другим вещам, над которыми я работаю.
Что ж, если у вас есть только 1 файл для одноразовой задачи, я бы остановился на NPP, но использовал бы его эффективно. Если вам нужно заменить , \n на ,\n\r, вам не нужно регулярное выражение, есть режим Расширенный. Если у вас есть больше файлов или в будущем будут аналогичные задачи, я бы просто написал скрипт Python с настраиваемыми параметрами. Я бы не стал использовать VBA. Кстати, с Python действительно легко разбирать JSON, просто import json.
@ WiktorStribiżew - это был не-RegEx пример чего-то, что замораживало RegEx до такой степени, что приходилось убивать задачу с теми же файлами. Это не решает мою проблему. (И файлов достаточно мало, я бы не возражал сделать это на NPP - если бы я мог вычислить RegEx для моей задачи - и если бы RegEx не зависал даже на предположительно более простой задаче.)
Итак, ваш вопрос - это просьба научить вас писать шаблоны регулярных выражений эффективный? В чем проблема настоящий? Я без проблем обрабатываю текстовые файлы размером 300 МБ с регулярным выражением в NPP. Тем не менее, я заработал 1/4 миллиона респондентов, отвечая на вопросы SO по регулярным выражениям. Я также знаю, когда использовать регулярное выражение (благодаря этому). Если у вас есть файлы JSON, используйте парсер JSON.
@ WiktorStribiżew Я не могу написать ни одного пригодного для использования RegEx, я потратил бесчисленное количество часов на RegExOne, RegEx101, Rexegg и т. Д .; это помеха. Конечная цель: получить все данные «между 2-й и 3-ей стрелками в примере» из файлов размером 40-80 МБ, чтобы выгрузить их в Access или SQL Server для анализа. Мне просто нужен один файл для правильной обработки, даже если мне придется делать это по одному activity за раз, тогда я могу автоматизировать повторение. (и, как я уже упоминал, «волшебное выражение RegEx», которое могло бы сделать это, также будет использовано для других целей.)
@ WiktorStribiżew Я не прошу урока и (как я уже упоминал) понимаю, что не должен просить кого-то написать для меня код (даже если он всего 10 символов!), И я даю новичкам за это дерьмо постоянно ... но я застрял, и, надеюсь, я заработал здесь достаточно Кармы, чтобы заслужить одно маленькое выражение лица. :) ... ох, и мне также очень любопытно, есть ли что-то особенное в Python, которое заставляет его так быстро обрабатывать файлы - но это больше из любопытства.
См. regex101.com/r/YQot4v/1, он соответствует заданному вами тексту. он не будет работать в Python, поскольку re не поддерживает притяжательные квантификаторы.
sweet - сейчас проверю на меньшем файле.
@ashleedawg: вы пометили свой вопрос с помощью Python, и вы ссылаетесь на скрипт Python, который, по-видимому, очень быстро анализирует этот файл, но между строк у меня создается впечатление, что вы ищете решение на VBA? Вы связываетесь с одной библиотекой и говорите, что она не может справиться с пропускной способностью. Вы считали Инструменты VBA / VBA-JSON?
@SimonShine Тег питон был запоздалой мыслью («почему Python делает это так быстро, а не VBA?») И только что заметил, что SO переместил его на передний план. Я не знаю Python; Удаляю метку - вводит в заблуждение. Также я связался с VBA-инструментами в своем вопросе. Я считаю VBA-JSON проблемным и ненадежным в условиях обычный и нефункциональным с файлами такого размера (но спасибо!)
@ WiktorStribiżew Красиво - спасибо ... разве что это будет легко перевернутый, так как цель состоит в том, чтобы удалить все, кроме выделения? Я бы проанализировал все совпадения ... за исключением того, что я не могу разобрать файл в VBA. (хотя, возможно, я мог бы выяснить, где вставить это Regex в файл Python, поскольку он каким-то образом анализирует файл.
@SimonShine - также для пояснения, файл Python быстро анализирует файл с различными критериями, и я не могу его настроить. Я включил файл как доказательство приложенных усилий и как решение аналогичной проблемы.
Вот когда обычно АЭС выходит из строя :) Регулярное выражение камикадзе для АЭС: см. шаблон регулярного выражения здесь и замените на (?{1}$1:\n).
@ashleedawg, реализация JSON-конвертер далеко не эффективна, и я сомневаюсь, что вы чего-то добьетесь с помощью регулярного выражения. С Json 40 МБ лучшее, что вы можете ожидать, - это более 10 секунд с VBA (см. JsonIO для более эффективной реализации).
@FlorentB. Я просто согласился с вами насчет VBA-JSON / JSON-Convertor выше. Для меня это было источником большого разочарования и потраченного времени. Спасибо за ссылку, я проверю JsonIO через некоторое время - в несвязанном проекте, который также включает JSON и VBA.

Вы можете попробовать это
(?s)^.*?\"longitude[^\[]*?\"activity[^\[]*\[[^\]]*?timestampMs\"[^\"\]]*\"(\d+)\"[^\]]*WALKING[^\]]*?confidence\"\s*:\s*(\b\d{1,3}\b)[^\]]*?\].*$
Демо Regex ,,, в котором я искал и приближался к целевым значениям захвата (timestamp value, walking value) с помощью таких ключевых слов, как "longitude", "activity", "[", "timestampMs", "]", "walking", "confidence".
Скрипт Python
ss = """ copy & paste the file contents' strings (above sample text) in this area """
regx= re.compile(r"(?s)^.*?\"longitude[^\[]*?\"activity[^\[]*\[[^\]]*?timestampMs\"[^\"\]]*\"(\d+)\"[^\]]*WALKING[^\]]*?confidence\"\s*:\s*(\b\d{1,3}\b)[^\]]*?\].*$")
matching= regx.match(ss) # method 1 : using match() function's capturing group
timestamp= matching.group(1)
walkingval= matching.group(2)
print("\ntimestamp is %s\nwalking value is %s" %(timestamp,walkingval))
print("\n"+regx.sub(r'\1 \2',ss)) # another method by using sub() function
Выход
timestamp is 1515564665992
walking value is 3
1515564665992 3
К сожалению, похоже, вы выбрали язык без производительного парсера JSON.
С Python у вас может быть:
#!/usr/bin/env python3
import time
import json
def get_history(filename):
with open(filename) as history_file:
return json.load(history_file)
def walking_confidence(history):
for location in history["locations"]:
if "activity" not in location:
continue
for outer_activity in location["activity"]:
confidence = extract_walking_confidence(outer_activity)
if confidence:
timestampMs = int(outer_activity["timestampMs"])
yield (timestampMs, confidence)
def extract_walking_confidence(outer_activity):
for inner_activity in outer_activity["activity"]:
if inner_activity["type"] == "WALKING":
return inner_activity["confidence"]
if __name__ == "__main__":
start = time.clock()
history = get_history("history.json")
middle = time.clock()
wcs = list(walking_confidence(history))
end = time.clock()
print("load json: " + str(middle - start) + "s")
print("loop json: " + str(end - middle) + "s")
В моей истории JSON размером 98 МБ это печатает:
load json: 3.10292s
loop json: 0.338841s
Это не очень эффективно, но, конечно, неплохо.
Obvious choices ...
Очевидным выбором здесь является инструмент с поддержкой JSON, который может быстро обрабатывать большие файлы. В дальнейшем я буду использовать jq, который может легко обрабатывать файлы размером с гигабайт быстро, пока имеется достаточно ОЗУ для хранения файла в памяти, и который также может обрабатывать очень большие файлы, даже если ОЗУ недостаточно для хранения JSON в памяти.
Во-первых, предположим, что файл состоит из массива объектов JSON показанной формы и что цель состоит в том, чтобы извлечь два значения для каждого допустимого подобъекта.
Это программа на jq, которая выполнит эту работу:
.[].activity[]
| .timestampMs as $ts
| .activity[]
| select(.type == "WALKING")
| [$ts, .confidence]
Для данного ввода это даст:
["1515564665992",3]
Более конкретно, предполагая, что указанная выше программа находится в файле с именем program.jq, а входным файлом является input.json, подходящий вызов jq будет следующим:
jq -cf program.jq input.json
Приведенную выше программу jq должно быть легко изменить для обработки других случаев, например если схема JSON более сложная, чем предполагалось выше. Например, если в схеме есть какие-то нарушения, попробуйте добавить постфиксные ?, например:
.[].activity[]?
| .timestampMs as $ts
| .activity[]?
| select(.type? == "WALKING")
| [$ts, .confidence]
Похоже на многообещающее приложение, но не совсем сработало. JQ1.5 / win64 разбился при каждой попытке (я Win7 / 64bit). JQ1.5 / Win32 запускался, но каждый файл выдавал ошибку, например: jq: error (at LocationHistory20180109.json:1734218): Cannot index array with string "activity", где 1734218 - это предпоследняя строка файла. jq: error (at LocationHistory20180109.json:1734218): Cannot index array with string "activity" Последние 2 строки: } ]}. Я полагаю, быстрое исправление? (Не удается разобрать последнее вхождение и т. д.?)
Также я предполагаю, что вы только что переименовали исполняемый файл с jq-win32 или jq-win64 в jq.exe?
Если введен недопустимый JSON, это действительно может быть проблемой, но если это просто нерегулярно, попробуйте добавить несколько?, Как предлагается в обновлении. Если это не сработает, возможно, вы могли бы показать последнюю часть файла, например. последний элемент в массиве верхнего уровня. (Чтобы проверить, достаточно ли введен JSON, попробуйте запустить: jq empty input.json)
Я создал образец файла для связывания или загрузки (я добавил ссылки на файлы в конце своего вопроса). Эта версия файла по-прежнему выдает ошибку в jq, но правильно проверяется онлайн. Я ценю ваши постоянные усилия; У меня еще не было времени попробовать другие ответы - они тоже выглядят многообещающими - хотя мне действительно нравятся звуки jq, и в качестве утилиты командной строки я также мог бы вызвать его программно. (Я удивлен, что не слышал об этом раньше!)
В файле pastebin есть интересующие вас элементы в .locations, поэтому вам, очевидно, придется соответствующим образом изменить программу jq (например, изменить исходный . на .locations). После этого все работает красиво.
честно, я пытался! Когда я сделал последнее изменение, вы предложили мне взять Cannot iterate over null (null). Я обнаружил онлайн-площадку и экспериментировал, но нигде не добился ... Вот фрагмент: jqplay.org/s/pcTR8mAbW_
В сниппете jqplay.org нет ни одного символа "?" в программе jq! В вашем примере вам нужен только первый: jqplay.org/s/1oOVOg568I
Думаю, я скопировал jq перед редактированием и не заметил изменений ... но Спасибо, он отлично работает даже на больших. Я приму твой ответ. Последний вопрос, мне нужно получить результат в Excel или Access. Должен ли я просто использовать >filename.txt в командной строке с jq или есть способ лучше?
Я бы использовал @tsv и сохранил как файл TSV (значения, разделенные табуляцией), с которым Excel (и другие) легко справятся.
Странно, что вам сложно работать с файлом размером 80 МБ в Notepad ++. У меня проблемы с работой с файлами размером 500 МБ, но 80 МБ - это нормально. ИМХО, вы должны сосредоточиться на решении своей основной проблемы, а не на «сжатии» JSON файла. Инструменты синтаксического анализа JSON должны без проблем работать с огромными файлами JSON.