Парсинг данных Excel в Apple Swift
Мой текущий рабочий процесс включает в себя использование Applescript для разделения данных Excel и форматирования их в простые текстовые файлы. Мы продвигаемся к созданию полностью Swift-среды, но я еще не нашел никаких наборов для разбора данных Excel в Swift.
Единственное, что я могу придумать, это использовать C или что-то еще и обернуть его, но это не идеально. Есть ли лучшие предложения по разбору этих данных для использования в Swift?
Цель состоит в том, чтобы устранить Applescript, но я не уверен, что это поможет быть возможным, все еще взаимодействуя с файлами Excel. Сценарий Excel с помощью Applescript, по-видимому, является единственным методом.
EDIT: у меня нет возможности исключить Excel из этого рабочего процесса. Именно так данные будут поступать в приложение, поэтому я должен их включить.
Возможность упростить процесс анализа этих данных, а затем их обработки будет иметь первостепенное значение. Я знаю, что Applescript был хорош в прошлом, помогая мне обрабатывать его; однако, он получает немного слишком замкнутый для меня.
Я смотрел на то, чтобы написать что-то в Swift/Cocoa, но это все еще может потребовать извлечения данных с помощью Applescript, верно?
Большим плюсом для толкания Swift является читабельность. Я не знаю Objective-C все это хорошо, и быстрый был бы более легким переходом, я чувствую.
Мой рабочий процесс на ПК использует объект COM, который, как уже было сказано, недоступен в приложении Mac Excel. Я только ищу извлечение данных на этом точка. Некоторые предыдущие приложения делали обработку внутри приложения, но я хочу сделать это очень автономным, таким образом, вся обработка в приложении, которое я разрабатываю. После того, как данные извлечены из .XLS или .XLSX файлы, я буду делать некоторые текстовые редактирования с помощью регулярных выражений и, возможно, немного хруст числа. Ничто не слишком сумасшедшим. На данный момент он будет работать на стороне клиента, но я хочу распространить его на серверный процесс.
4 ответов:
В Mac OS X 10.6 Snow Leopard Apple представила платформу AppleScriptObjC, которая позволяет очень легко взаимодействовать между Cocoa и AppleScript. Код AppleScript и синтаксис Objective-C могут использоваться в одном исходном файле. Это гораздо удобнее, чем
Scripting BridgeиNSAppleScript.AppleScriptObjC не может использоваться непосредственно в Swift, поскольку команда
loadAppleScriptObjectiveCScriptsNSBundle не соединена с Swift.Однако вы можете использовать класс Objective-C bridge для пример
ASObjC.h
@import Foundation; @import AppleScriptObjC; @interface NSObject (Excel) - (void)openExcelDocument:(NSString *)filePath; - (NSArray *)valueOfUsedRange; @end @interface ASObjC : NSObject + (ASObjC *)sharedASObjC; @property id Excel; @endASObjC.m
#import "ASObjC.h" @implementation ASObjC + (void)initialize { if (self == [ASObjC class]) { [[NSBundle mainBundle] loadAppleScriptObjectiveCScripts]; } } + (ASObjC *)sharedASObjC { static id sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[ASObjC alloc] init]; }); return sharedInstance; } - (instancetype)init { self = [super init]; if (self) { _Excel = NSClassFromString(@"ASExcel"); } return self; } @endСоздайте исходный файл AppleScript из шаблона AppleScriptObjC
ASExcel.applescript
script ASExcel property parent: class "NSObject" on openExcelDocument:filePath set asFilePath to filePath as text tell application "Microsoft Excel" set sourceBook to open workbook workbook file name asFilePath repeat try get workbooks return end try delay 0.5 end repeat end tell end openDocument on valueOfUsedRange() tell application "Microsoft Excel" tell active sheet set activeRange to used range return value of activeRange end tell end tell end valueOfUsedRange end scriptСсылка на фреймворк AppleScriptObjC, если это необходимо.
Создайте заголовок моста и импортируйтеASObjC.hТогда вы можете вызвать AppleScriptObjC из Swift с помощью
ASObjC.sharedASObjC().Excel.openExcelDocument("Macintosh HD:Users:MyUser:Path:To:ExcelFile.xlsx")Или
let excelData = ASObjC.sharedASObjC().Excel.valueOfUsedRange() as! Array<[String]>
Несколько неясно, пытаетесь ли вы устранить Excel как зависимость (что не является необоснованным: он стоит денег и не у всех есть) или AppleScript как язык (полностью понятный, но плохой практический шаг, поскольку альтернативы Apple для автоматизации приложений все сосут).
Существуют сторонние библиотеки Excel-синтаксического анализа, доступные для других языков, например, я использовал Python'S
openpyxl(for .xlsx файлы) иxlrd(для .xsl) библиотеки успешно работают в моих собственных проектах. И я смотрите сквозь магию Гуглов, что кто-то написал фреймворк ObjC, DHlibxls, который [предполагая отсутствие динамического обмана] должен использоваться непосредственно из Swift, но я сам не использовал его, поэтому не могу сказать вам ничего больше.
Вы можете использовать ScriptingBridge и NSAppleScript, чтобы взаимодействовать с Apple сценарных материалов
ScriptingBridge может генерировать заголовочный файл из словаря сценариев Apple.
NSAppleScript может выполнить любой помощью AppleScript для вас путем передачи
String
1. Экспорт в текстовый файл CSV
Если все, что вы пытаетесь сделать, это извлечь данные из Excel для использования в другом месте, в отличие от захвата формул Excel и форматирования, то вам, вероятно, не следует пытаться читать .xls-файл. XLS-это сложный формат. Это хорошо для Excel, а не для общего обмена данными.
Точно так же вам, вероятно, не нужно использовать AppleScript или что-либо еще для интеграции с Excel, если все, что вы хотите сделать, это сохранить данные в виде открытого текста. Excel уже знает как сохранить данные в виде открытого текста. Просто используйте команду Excel "Сохранить как". (Так это называется на Mac. Я ничего не знаю о компьютерах.)
Вопрос в том, какой формат открытого текста использовать. Одним из очевидных вариантов для этого являетсятекстовый файл значений, разделенный запятыми (CSV) , потому что это простой стандарт де-факто (в отличие от сложного официального стандарта, такого как XML). Это позволит легко потреблять в Swift или на любом другом языке.2. Экспорт в кодировке UTF-8, если это возможно, иначе как UTF-16
Так как вы делаете, что именно? Открытый текст удивительно прост, но одна тонкость, которую вам нужно отслеживать, - это кодировка текста . Кодировка текста-это способ представления символов в текстовом файле. К сожалению, вы не можете достоверно определить кодировку файла, просто проверив его, поэтому вам нужно выбрать кодировку при сохранении и не забыть использовать эту кодировку при чтении. Если вы все испортите, акцентированные символы, типографские кавычки, тире и другие символы, отличные от ASCII, будут искажены. Итак, какую кодировку текста вы должны использовать? Короткий ответ: вы должны всегда использовать UTF-8, если это возможно .
Но если вы работаете со старой версией Excel, то вы не сможете использовать UTF-8. В этом случае следует использовать UTF-16. В частности, UTF-16, я считаю, единственный вариант экспорта в Excel 2011 для Mac, который дает предсказуемый результат, который не будет зависеть удивительным образом от неясных настройки локали или кодировки, специфичные для Microsoft.Итак, если вы используете Excel 2011 для Mac, например, выберите "UTF-16 Unicode Text"из команды Excel Save As.
Это приведет к тому, что Excel сохранит файл так, что каждая строка будет строкой текста, а каждый столбец будет разделен символом табуляции. (Таким образом, технически это разделенные табуляцией файлы значений, а не разделенные запятыми файлы значений.)3. Импорт с помощью Swift
Теперь у вас есть текстовый файл, который, как вы знаете, был сохранено в кодировке UTF-8 (или UTF-16). Так что теперь вы можете прочитать его и разобрать в Swift.
Если ваши данные Excel сложны,вам может понадобиться полнофункциональный анализатор CSV. лучший выбор, вероятно, CHCSVParser.
Используя CHCSV, вы можете проанализировать файл со следующим кодом:
NSURL * const inputFileURL = [NSURL fileURLWithPath:@"/path/to/exported/file.txt"]; unichar tabCharacter = '\t'; NSArray *rows = [NSArray arrayWithContentsOfCSVFile:inputFilePath options:CHCSVParserOptionsSanitizesFields delimiter:tabCharacter];(вы также можете позвонить из Swift, конечно.)
С другой стороны, если ваши данные относительно просты (например, в них нет экранированных символов), то вы возможно, вообще не потребуется использовать внешнюю библиотеку. Вы можете написать некоторый Swift-код, который анализирует значения, разделенные табуляциями, просто читая в файле в виде строки, разбивая на новые строки, а затем разбивая на вкладки.
Эта функция возьмет
String, представляющий данные TSV, и вернет массив словарей:Таким образом, вам нужно только прочитать файл в строку и передать его этой функции. Этот фрагмент происходит из этой сути для конвертера tsv-to-json. И если вам нужно знать больше о том, какие текстовые кодировки производят продукты Microsoft, и какие из них Cocoa может автоматически обнаруживать, тогда это репо по текстовому кодированию содержит исследования по экспортным образцам, которые привели к выводу, что UTF-16-это способ пойти для старых продуктов Microsoft на Mac./** Reads a multiline, tab-separated String and returns an Array<NSictionary>, taking column names from the first line or an explicit parameter */ func JSONObjectFromTSV(tsvInputString:String, columnNames optionalColumnNames:[String]? = nil) -> Array<NSDictionary> { let lines = tsvInputString.componentsSeparatedByString("\n") guard lines.isEmpty == false else { return [] } let columnNames = optionalColumnNames ?? lines[0].componentsSeparatedByString("\t") var lineIndex = (optionalColumnNames != nil) ? 0 : 1 let columnCount = columnNames.count var result = Array<NSDictionary>() for line in lines[lineIndex ..< lines.count] { let fieldValues = line.componentsSeparatedByString("\t") if fieldValues.count != columnCount { // NSLog("WARNING: header has %u columns but line %u has %u columns. Ignoring this line", columnCount, lineIndex,fieldValues.count) } else { result.append(NSDictionary(objects: fieldValues, forKeys: columnNames)) } lineIndex = lineIndex + 1 } return result }(я понимаю, что здесь я связываюсь со своими собственными РЕПО. Извинения?)
Comments