Mathcad: как обработать файл со смешанными числовыми и строковыми данными?
Чтение и обработка матрицы или вектора из текстового файла в Mathcad выглядят довольно просто:
- Функция
READPRN("имя файла")
возвращает матрицу, в которой каждая строка определяется записью (строкой) файла. Количество элементов (числовых значений) в каждой строке файла должно быть одинаковым. Используется в видеA:= READPRN("имя файла")
, гдеA
- массив; - Функция
WRITEPRN("имя файла")
записывает матрицу в файл данных. Каждая строка матрицы становится записью файла. Используется в видеWRITEPRN("имя файла"):=A
, гдеA
- массив; - Функция
APPENDPRN("имя файла")
дописывает матрицу к существующему файлу. Используется в видеAPPENDPRN("имя файла"):=A
. Существующий файл должен иметь столько же столбцов, что и массивA
.
Эти функции предназначены для работы со структурированным файлом данных, то есть, файлом, содержащим числа, расположенные по строкам и столбцам. Как частный случай, файл может содержать одну строку или один столбец с числами, то есть, быть вектор-строкой или вектор-столбцом.
В качестве практического примера решим такую задачку:
В файле содержится матрица оценок
N
студентов поM
предметам,N>1, M>0
. Прочитать данные и вычислить следующие величины:
- средний балл по каждому предмету и каждому студенту;
- общий средний балл группы;
- количество оценок "2", "3", "4" и "5".
Если исходные данные сохранены в файле data.txt
вида
3 4 5 5 4 3 3 3 3 5 5 5 3 2 3
то полный код решения выглядит так:
чтение и запись матрицы в Mathcad
Если файл "неправильный", то есть, не содержит одинаковое количество числовых значений в каждой строке, то функция READPRN
его не прочитает. Дополнительно мы проверяем, содержатся ли в файле допустимые оценки (то есть, значения 2, 3, 4 или 5) с помощью переменной Check
.
Результаты пишутся в файл result.txt
текущей папки, вот что там вышло:
3 4 5 4 5 4 3 4 3 3 3 3 5 5 5 5 3 2 3 2.667 3.8 3.6 3.8 0
Нижний правый ноль пришлось добавить, чтобы APPENDPRN
не отказывалась дописывать в файл вектор-строку со средними баллами по трём предметам.
Чтобы этот код заработал, нужно выполнение 3 условий:
- документ MathCAD был хотя бы раз сохранен;
- текстовый файл
data.txt
был сохранен в той же папке, что и документ MathCAD; - в текстовом файле содержатся только числовые значения, причём, их количество в каждой строке файла одинаково (количество пробелов или табуляций между значениями в одной строке не имеет значения).
Скачать этот пример в архиве .zip с файлом .xmcd Mathcad 15 и файлом данных (17 Кб)
Что в нашем решении оказалось неудобно? Прежде всего то, что студенты из списка отличаются между собой только по номерам. Можно ли сделать так, чтобы Mathcad читал нормальный текстовый файл с текстом и числами, да ещё и позволял иметь разное количество разделителей в строках и разное количество чисел в одной строке?
Для решения такой задачи удобно использовать панель программирования и функцию READCSV
, предназначенную для чтения произвольных текстовых данных.
Функция доступна в Mathcad версии 15
Правда, при "ручной" обработке данных нам придётся проделать подготовительную работу по "чистке" и парсингу прочитанных из файла строк.
Подготовим следующие функции:
char(s,i)
- извлечение из строкиs
символа с допустимым номеромi
;isdiv(s)
- проверяет, является ли односимвольная строкаs
разделителем, то есть, пробелом, табуляцией или переводом строки. Возвращает 0 или 1;trimstr(s)
- удаляет лишние разделители в начале, конце строки, а также между лексемами. Возвращает строку из лексем, разделённых одним пробелом.
Функции char и isdiv (Mathcad)
Функция trimstr (Mathcad)
Значение системной настройки ORIGIN
предполагается равным нулю (по умолчанию), опция Тооls - Worksheet options - Calculations - Use ORIGIN to string indexing
не установлена, то есть, строки индексируются всегда с нуля независимо от значения ORIGIN
, это тоже принято по умолчанию.
Теперь мы готовы написать функцию, которая парсит матрицу из одного столбца, содержащую записи следующего вида (файл test.txt
):
Иванов 3 4 5 Петров 4 4 5
функция parse (Mathcad)
Функция предполагает, что первая из оставшихся после обработки trimstr
в очередной строке лексема является строкой, попадающей в массив Names
, а остальные лексемы - числовые значения, записываемые в матрицу Balls
.
Существенно, что эту функцию не должны смущать не-число в данных Balls
(в соответствующую позицию матрицы запишется ноль, см. оператор on error
) или разное количество чисел в строке (Mathcad автоматически "расширит" матрицу, заполняя свободные столбцы нулями).
Текстовый файл test.txt
сохранён в кодировке Юникод (UTF-8), в этом случае мой новенький Mathcad 15 M045 прочитал символы кириллицы без проблем.
Остаётся проверить, что получилось, а дальше использовать массивы Names
и Balls
по своему усмотрению, например, как в предыдущей задаче.
тест функции parse (Mathcad)
Скачать этот пример в архиве .zip с файлом .xmcd Mathcad 15 и файлом данных (34 Кб)
P.S. Весь наш длинный код следует рассматривать, конечно, как учебный. Реально мы могли бы, настроив чтение функцией READCSV, решить задачу в 3 строчки кода:
READCSV - короткий код для чтения из файла CSV
Файл list.txt
содержал лишние разделители, будучи таким:
Иванов 3 4 5 Петрова 4 4 5
Если файл сохранён из Блокнота, выбрать при сохранении кодировку Юникод или UTF-8, метка BOM Mathcad'у помешать не должна. Также функцию не смутят "недостающие" числа в данных, в нашем случае она заменит их нулями.
24.03.2016, 14:35 [15472 просмотра]