Введение

Пару дней назад мне написал знакомый студент-физик с просьбой помочь открыть данные, снятые с лабораторного оборудования в Excel и скинул мне несколько файлов странного формата .mmd. Интернет на запрос "как открыть mmd", выдавал только танцующих аниме-девочек (MikuMikuDance) и сайт разработчика mangodata, с которого нельзя было скачать нужное ПО. Конечно, с подобной проблемой столкнется далеко не каждый, но прецедент в моем лице появился, а это значит, что интернету нужна статья "Открываем MMD формат в Excel".

Пошаговое руководство

Для тех, кому надо просто открыть файл, не вдаваясь в подробности. Если вы знакомы с Google Colab, вас заинтересует только второй пункт. Писать старался максимально подробно, демонстрируя каждое действие. Перед тем как выполнять шаги, лучше прочесть руководство целиком.

1. Заходим в Google Colab

Google Colab - удобная среда выполнения кода на Python. Не пугаемся, если испугались. Навыков питониста (да и вообще программиста) от вас не требуется. Я сам не являюсь python-программистом. Использую его, только когда нужно быстро решить задачку с использованием кода.
Переходим по ссылке https://colab.research.google.com

Тот самый скрин выше
Тот самый скрин выше

2. Скачиваем colab-блокнот или создаем его сами

Можете скачать файл с моего Google Drive по ссылке:

https://drive.google.com/file/d/1lA3-1Z1kiVmlrUsrv-THvvrT8bRcZMHn/view?usp=sharing

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

Чтобы открыть файл MMDtoCSV.ipynb в колабе, нажимаем Загрузить в окне со скрина выше или Файл - Загрузить блокнот в основном меню.

Готовый colab-блокнот
Готовый colab-блокнот

Вы так же можете не скачивать мой файл, а просто скопировать готовый код в колаб. Для этого нажимаем +Код

Копируем в созданный блок данный код:

mmd_file_name = "file_name.mmd" # write your mmd file name here
mmdfile = open(mmd_file_name,"r")
mmddata = mmdfile.read()
startpos = mmddata.find('"data":[[')+8
endpos = mmddata[startpos:].find(']]')+1
data = mmddata[startpos:endpos]
data = data.replace('],[','\n')
data = data.replace('[','')
data = data.replace(']','')
csvfile = open("csvfile.csv","w")
csvfile.write(data)
csvfile.close()

3. Загружаем в колаб свой файл и запускаем код

Перетаскиваем ваш mmd файл в окно Файлы

В форме ниже нажимаем Ок.

В самой первой строчке кода меняем название файла на своё.

Здесь меняем file_name на название своего файла
Здесь меняем file_name на название своего файла

Запускаем код. Для этого можно нажать Ctrl+F9.

4. Скачиваем и открываем сконвертированный файл

После выполнения кода в Файлах появится файл csvfile.csv

Если этого не произошло, обновите папку, нажав соответствующую кнопку.

Обновить содержимое
Обновить содержимое

Скачиваем получившийся файл и открываем его в Excel (Данные - Из CSV-файла).

Как открыть CSV-файл в Excel
Как открыть CSV-файл в Excel

5. Наслаждаемся результатом

А что мы только что сделали?

Раздел для новичков, не обладающих знаниями о форматах данных, но жаждущих получить ответ на этот вопрос.

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

//пример mmd-файла
{
	"author":"User",
	"recordingDevice":"Windows NT 10.0",
	"date":1636465537725,"sampleRate":100,
	"configuration":{
				"decimals":null,
				"movingAverage":25,
				"mode":null,
				"measurementType":"continuous",
				"pointMeasurementNumbers":null,
				"diagramType":"line",
				"xAxis":null,
				"xAxisDeviceId":null,
				"lastMeasurement":null,
				"additionalYAxis":null,
				"radioactivityGateTime":1,
				"dropCounterVolume":0.05,
				"dropCounterTotalVolume":1
	},
	"channels":[{"id":1,"uid":"60-E9:63:CD:A8:07:84-1","sensor":{"id":60},"unit":"V","color":"#CC5045"},{"id":1,"uid":"60-EA:75:68:B2:3C:0A-1","sensor":{"id":60},"unit":"V","color":"#E49128"}],
	"data":[[0,0.005,-0.149],[0.01,-0.002,-0.134],[0.02,0.005,-0.134]],
	"annotations":null
}

Метаданные (author, date и др.) нас в данном кейсе не интересуют. Всё, что нужно сделать - достать содержимое, хранящееся под ключом data. Заметим, что данные хранятся в двумерном массиве.

Находим в файле подстроку ' "data":[[ ' и запоминаем ее позицию. Затем ищем первое (начиная с data:[[) вхождение подстроки ' ]] ' - две квадратные скобки подряд определяют конец двумерного массива:

startpos = mmddata.find('"data":[[')+8
endpos = mmddata[startpos:].find(']]')+1

Запоминаем все объекты двумерного массива:

data = mmddata[startpos:endpos]

Вот так выглядит содержимое переменной data:

[0,0.005,-0.149],[0.01,-0.002,-0.134],[0.02,0.005,-0.134]

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

Пример CSV-файла
Пример CSV-файла

Внутри одной строки в нашем файле данные уже разделены запятыми. Отделить друг от друга ряды можно, заменив ' ],[ ' на символ переноса строки ' \n '.

data = data.replace('],[','\n')
//результат
[0,0.005,-0.149
0.01,-0.002,-0.134
0.02,0.005,-0.134]

Удаляем две оставшиеся по краям скобки ' [ ' и ' ] ' и сохраняем итоговый результат в формате csv.

data = data.replace('[','')
data = data.replace(']','')
csvfile = open("csvfile.csv","w")
csvfile.write(data)
csvfile.close()

Теперь можно экспортировать данные в Excel.

Комментарии (8)


  1. eugene08
    04.01.2022 23:04
    +2

    Лучше использовать готовые библиотеки, https://www.geeksforgeeks.org/read-json-file-using-python/ + https://docs.python.org/3/library/csv.html. Но есть минус, на статью не потянет.


  1. staticmain
    04.01.2022 23:18
    +6

    Можно было открыть в notepad++,удалить руками всё кроме данных в data и заменить "], [" на символ переноса. Первую и последнюю оставшуюся скобку просто удалить.


  1. shark14
    04.01.2022 23:29
    +3

    Какой-то невероятно костыльный способ для того, чтобы рекомендовать его в статье.

    Если у вас появится пробельный символ (в том числе перевод строки) в разделителе ],[, то все сломается, хотя это по-прежнему будет валидный JSON. Чтобы от такого не зависеть, лучше распарсить JSON, используя готовые решения, и вытащить оттуда нужные части.

    Ну и в питоновском коде хорошей практикой является использование конструкции with (with open('myfile.txt') as f) при работе с файлами: https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files


  1. bozman
    04.01.2022 23:31
    +3

    А зачем ковырять JSON реплейсами? Вот в JS, например. В Python, ЕМНИП, тоже пара строк, но на память не вспомню. Тоже парсим JSON и вынимаем значения как массив массивов...

    const d3 = require('d3');

    let result = d3.csvFormat(JSON.parse(mmdfilecontent).data)


  1. igor6130
    04.01.2022 23:55
    +4

    Не совсем понимаю, если MMD — это по сути JSON, то зачем все эти find() и replace()? Есть же встроенный в Питон модуль json с load() и dumps().


    1. Gengenid
      05.01.2022 00:01
      +4

      Excel и сам может распарсить json через powerquery


  1. runaway
    05.01.2022 16:01
    +1

    Я в своё время подобные файлы парсил в Матлабе. Если структура файлов фиксированная, не очень трудно выдернуть нужные данные средставми Матлаба.


  1. 13werwolf13
    06.01.2022 22:04

    колаб, питон..

    для этой задачи хватит sed и cut в одну строку..