Converting Docx Files To Text In Swift - swift

I have a .docx file in my temporary storage:
let location: NSURL = NSURL.fileURLWithPath(NSTemporaryDirectory())
let file_Name = location.URLByAppendingPathComponent("5 November 2016.docx")
What I now want to do is extract the text inside this document. But I cannot seem to find any converters or methods of doing this.
I have tried this:
let file_Content = try? NSString(contentsOfFile: String(file_Name), encoding: NSUTF8StringEncoding)
print(file_Content)
However it prints nil.
So how do I read the text in a docx file?

Swift 4, Xcode 9.1, OSX targets from 10.10 to 10.13
I have found that the following code extracts text handily from a Word .doc file, which then easily goes into a string. (The attributed string contains formatting information that might be parsed to good effect.) The main info that I wanted to convey was the bit about using .docFormat to specify the document type.
let openPanel = NSOpenPanel()
var fileString = String("")
var fileData = NSData()
let fileURL = openPanel.url
do {
fileData = try NSData(contentsOf: fileURL!)
if let tryForString = try? NSAttributedString(data: fileData as Data, options: [
.documentType: NSAttributedString.DocumentType.docFormat,
.characterEncoding: String.Encoding.utf8.rawValue
], documentAttributes: nil) {
fileString = tryForString.string
} else {
fileString = "Data conversion error."
}
fileString = fileString.trimmingCharacters(in: .whitespacesAndNewlines)
} catch {
print("Word Document File Not Found")
}

Your initial issue is with how you get the string from the URL. String(File_Name) is not the correct way to convert a file URL into a file path. The proper way is to use the path function.
let location = NSURL.fileURLWithPath(NSTemporaryDirectory())
let fileURL = location.URLByAppendingPathComponent("My File.docx")
let fileContent = try? NSString(contentsOfFile: fileURL.path, encoding: NSUTF8StringEncoding)
Note the many changes. Use proper naming conventions. Name variables more clearly.
Now here's the thing. This still won't work because a docx file is a zipped up collection of XML and other files. You can't load a docx file into an NSString. You would need to use NSData to load the zip contents. Then you would need to unzip it. Then you would need to go through all of the files and find the desired text. It's far from trivial and it is far beyond the scope of a single stack overflow post.

Related

How to edit and update xml file with Swift

I'm trying to merge two xml files to a new xml file. Also adding one line <xxxxxxxxxxXML Seperatorxxxxxxxxxx> in between two xml.
I'm using SWXMLHash pod to parser my xml file. I already have two var of xml that I need to merge. Thanks!
var oldXML: XMLIndexer?
var newXML: XMLIndexer?
var combinedXML: XMLIndexer?
func mergeEHR(oldXML: XMLIndexer, newXML: XMLIndexer) -> XMLIndexer {
do {
/// Don't know how to merge it.
} catch {
print(error)
}
}
I want it to be
var combinedXML =
<oldXML>
...
</oldXML>
xxxxxxxxxxXML Seperatorxxxxxxxxxx
<newXML>
...
</newXML>
Since combined XML will be not a valid XML (even if it was, doesn't matter), treat them as a raw String:
let oldXMLString = try! String(contentsOfFile: <#PathToOldXML#>) // If it is on the file, else assign it the way it should
let separator = "<xxxxxxxxxxXML Seperatorxxxxxxxxxx>"
let newXMLString = try! String(contentsOfFile: <#PathToNewXML#>) // If it is on the file, else assign it the way it should
let combinedXMLString = [oldXMLString, separator, newXMLString].joined(separator: "\n")
try! combinedXMLString.write(toFile: <#PathToDestinationOfTheCombinedXML#>, atomically: <#Bool#>, encoding: <#String.Encoding#>)
Then you can treat the result as an invalid XML or etc. again.

Saving multiple lines of text in swift

I am attempting to store multiple lines of text in a local text file on an iphone. I have code which will create a text document, write data to that document and read data from this document.
However, if i try and add more text to this document, it will only store the most recent line of text which has been added.
The code I have for creating, writing and reading text from this document is as follows:
//Storing user rewards
let fileName = "Rewards"
let DocumentDirURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = DocumentDirURL.appendingPathComponent(fileName).appendingPathExtension("txt")
//print("File Path: \(fileURL.path)")
let writeString = rewardLBL.text
do {
//writing to the file
try writeString?.write(to: fileURL, atomically: true, encoding: String.Encoding.utf8)
} catch let error as NSError{
print("failed to write")
print(error)
}
var readString = ""
do {
readString = try String(contentsOf: fileURL)
}catch let error as NSError{
print("failed to readFile")
print(error)
}
print(readString)
I need this to allow for multiple entries of text to be stored, rather than just the most recent data which was written.
I suspect that due to the code being inside the 'viewDidLoadi()' method that it is constantly recreating the same document and thus always making a new version which overwrites the old Rewards.txt document.
Any help is greatly appreciated, thanks.
Since you are using write, it will overwrite whatever is written earlier.
try writeString?.write(to: fileURL, atomically: true, encoding:
String.Encoding.utf8)
You need to append line of text to your file, which will not overwrite previous written lines. Something like this:
writeString.data(using: String.Encoding.utf8)?.write(to: fileURL, options: Data.WritingOptions.withoutOverwriting)

Write to file not working (Swift 4)

I am starting learning about Swift programming. Up to now, I have already developed my first working app. Although simple, it is a very useful one. But with the introduction of Swift 4 and XCode 9, I'm facing some headaches. Right now I am trying to write a small piece of code to write a string to a file, like this:
let fileName = "myFile.txt"
let path = NSURL(fileURLWithPath:
NSTemporaryDirectory()).appendingPathComponent(fileName)
var myText = "Some text to write to file"
do {
try myText.write(to: path!, atomically: true, encoding: UTF8)
} catch {
// Handle error
}
When I write myText.write, XCode suggests the above syntax, but right after I choose it and fill the placeholders, XCode displays the error "Extra argument 'atomically' in call. Note that it is the very structure it suggested. I haven't found any workaround until now. Can anyone help me?
The error is misleading. The encoding parameter is wrong
try myText.write(to: path!, atomically: true, encoding: .utf8)
And don't use NSURL in Swift 3+, use native URL:
let url = URL(fileURLWithPath: ...
However I recommend this way
let fileName = "myFile.txt"
let url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
let myText = "Some text to write to file"
let data = Data(myText.utf8)
do {
try data.write(to: url, options: .atomic)
} catch {
print(error)
}

How do I convert a file into a JSON Object in SwiftyJson

I am trying to import Json data from a user uploaded txt file into a standard object that I can use via SwiftyJson framework
Here is the contents of the text fie:
{
"String": "answer",
"String2": "answer2"
}
I have successfully read it and turned it into a String file using:
let openPanel = NSOpenPanel()
let arrayOfExtensions = ["txt"]
openPanel.allowedFileTypes = arrayOfExtensions
let result = openPanel.runModal()
if result == NSFileHandlingPanelCancelButton {
return
}
let fileUrl = openPanel.URL
do {
let stringResult = try String(contentsOfURL: fileUrl!, encoding: NSUTF8StringEncoding)
print (stringResult)
completionhandler(retrievedData: stringResult, error: nil)
I am trying to convert this into a JSON object using:
let jsonFile = JSON(contentsOfFile)
The problem is that the resulting JSON object created appears to be blank for all the fields except rawvalue.
Here is the screenshot from the debug console.
How to I sucessfully read in the string from the file and then make it populate via SwiftJson correctly?
The problem above was that I was using the wrong method to parse it into JSON.
SwiftyJSON seems to be badly documented hence others had a similar problem.
The correct way to do this is to use :
let jsonFile = JSON.parse(string:contentsOfFile)

Simple way to read local file using Swift?

I'm trying to learn the new Swift programming language. It looks great, but I'm having a difficult time doing something as simple as reading the content of a local .txt file.
I have tried the few examples I could find through Google, but they give compile errors, like this answer here: Read and write data from text file
If I tweak the code a bit, it works, but can only read from a special location within the project.
Why isn't it just as simple to read a .txt file with Swift as it is with for instance Ruby? And how would I go about reading the content of a file located at ~/file.txt?
Thnx
If you have a tilde in your path you can try this:
let location = "~/file.txt".stringByExpandingTildeInPath
let fileContent = NSString(contentsOfFile: location, encoding: NSUTF8StringEncoding, error: nil)
otherwise just use this:
let location = "/Users/you/Desktop/test.txt"
let fileContent = NSString(contentsOfFile: location, encoding: NSUTF8StringEncoding, error: nil)
This gives you a string representation of the file, which I assumed is what you want.
You can use NSData(contentsOfFile: location) to get a binary representation, but you would normally do that for, say, music files and not a text file.
Update: With Xcode 7 and Swift 2 this doesn't work anymore. You can now use
let location = NSString(string:"~/file.txt").stringByExpandingTildeInPath
let fileContent = try? NSString(contentsOfFile: location, encoding: NSUTF8StringEncoding)
let file = "/Users/user/Documents/text.txt"
let path=URL(fileURLWithPath: file)
let text=try? String(contentsOf: path)
This would work:
let path = "~/file.txt"
let expandedPath = path.stringByExpandingTildeInPath
let data: NSData? = NSData(contentsOfFile: expandedPath)
if let fileData = data {
let content = NSString(data: fileData, encoding:NSUTF8StringEncoding) as String
}
Note that data may be nil, so you should check for that.
EDIT:
Don't forget conditional unwrapping - looks much nicer ;)
Relative path tip:
Instead of doing this:
NSString("~/file.txt").stringByExpandingTildeInPath
You can do this:
"\(NSHomeDirectory())/file.txt"
You may find this tool useful to not only read from file in Swift but also parse it simultaneously: https://github.com/shoumikhin/StreamScanner
Just specify the file path and data delimiters like this (see readme for more options):
import StreamScanner
if let input = NSFileHandle(forReadingAtPath: "/file/path")
{
let scanner = StreamScanner(source: input, delimiters: NSCharacterSet(charactersInString: ":\n")) //separate data by colons and newlines
while let field: String = scanner.read()
{
//use field
}
}
Hope, this helps.
Using the answer by Atomix, this will work in Swift 4:
let location = NSString(string: "~/test.txt").expandingTildeInPath
let fileContent = try? NSString(contentsOfFile: location, encoding: String.Encoding.utf8.rawValue)
This worked for me in Swift 2.1, XCode7 to get the location and print the contents of CSV. ( you can create a simple CSV in Text Wrangler)
override func viewDidLoad() {
super.viewDidLoad()
let location = NSString(string:"/Users/*Myusername*/Documents/myCSVfile.csv")
let fileContent = try? NSString(contentsOfFile: location as String, encoding: NSUTF8StringEncoding)
print(fileContent)
}
Swift 4:
let filePath = "/Users/UserName/Desktop/FolderName/FileName.txt"
let fullPath = NSString(string: filePath).expandingTildeInPath
do
{
let fileContent = try NSString(contentsOfFile: fullPath, encoding: String.Encoding.utf8.rawValue)
print(fileContent)
}
catch
{
print(error)
}
filename doesn't need to have scheme like file://, and can be relative like ../docs/test.txt.
Remember to catch any error thrown, or rethrow.
let url = URL(fileURLWithPath: filename)
let contents = try String(contentsOf: url, encoding: .utf8)