I was wondering what the simplest and cleanest to read a text file into an array of strings is in swift.
Text file:
line 1
line 2
line 3
line 4
Into an array like this:
var array = ["line 1","line 2","line 3","line 4"]
I would also like to know how to do a similar thing into struct like this:
Struct struct{
var name: String!
var email: String!
}
so take a text file and put it into struct's in an array.
Thanks for the help!
First you must read the file:
let text = String(contentsOfFile: someFile, encoding: NSUTF8StringEncoding, error: nil)
Then you separate it by line using the componentsSeparatedByString method:
let lines : [String] = text.componentsSeparatedByString("\n")
Updated for Swift 3
var arrayOfStrings: [String]?
do {
// This solution assumes you've got the file in your bundle
if let path = Bundle.main.path(forResource: "YourTextFilename", ofType: "txt"){
let data = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
arrayOfStrings = data.components(separatedBy: "\n")
print(arrayOfStrings)
}
} catch let err as NSError {
// do something with Error
print(err)
}
Updated for Swift 5:
The const path contains the file path.
do {
let path: String = "file.txt"
let file = try String(contentsOfFile: path)
let text: [String] = file.components(separatedBy: "\n")
} catch let error {
Swift.print("Fatal Error: \(error.localizedDescription)")
}
If you want to print what's inside of file.txt line by line:
for line in text {
Swift.print(line)
}
Here is a way to convert a string to an array(Once you read in the text):
var myString = "Here is my string"
var myArray : [String] = myString.componentsSeparatedByString(" ")
This returns a string array with the following values: ["Here", "is", "my", "string"]
Swift 4:
do {
let contents = try String(contentsOfFile: file, encoding: String.Encoding.utf8)
let lines : [String] = contents.components(separatedBy: "\n")
} catch let error as NSError {
print(error.localizedDescription)
}
In Swift 3 for me worked like below:
Import Foundation
let lines : [String] = contents.components(separatedBy: "\n")
Related
I have a code like this :
// Language = Dart
var someVariable = 'Hello';
var someOtherVariable = 'World';
var str = 'somedomain?x=${someVariable}&y=${someOtherVariable}';
return str;
// Expected:
// somedomain?x=Hello&y=World;
// Actual
// somedomain?x=Hello
If I replace the & character with any alphabets, it is able to successfully concatenate. What am I doing wrong.
This is the actual code which I used in FlutterFlow, and am having issues with:
Future<String> getEventUrlFromReference(BuildContext context, DocumentReference? eventReference) async {
var userId = currentUser?.uid as String;
return "https://somedomain.com/event?eventReference=${eventReference?.id}" + "&invitedBy="+userId;
}
// result: https://somedomain.com/event?eventReference=referencevalue
This was a string encoding issue. I was using the result of my function/code as body text in sms://<number>?&body=<string_containigng_&_character>; The text which is appended to the sms text truncates at the & character, and I made a mistake assuming it's a string concatenation issue.
I'm creating a performance test with Jmeter and I need to create a body request like this:
{
[ "objectName1", "objectName2", ..., "objectNameN" ]
}
so need to create a Groovy script to build this request according to a certain .csv file with the objects names. And I have done something like this:
//Default separator
char SEPARATOR = ',';
String csvFile = props.get("csvPathAndName")
log.info('__________________________________________________________________________________________________________________________________________________________')
log.info(csvFile)
//function to read csv file
def readLines(String csvFile) {
File file = new File(csvFile);
List<String> objectNames = file.readLines();
// objectsNames.stream().forEach(e -> listOfString + ", " + e);
vars.put("listOfObjects", "'objectName1', 'objectName2', 'ObjectName3'");
}
readLines(csvFile)
Notice that in line
vars.put("listOfObjects", ...
I want to populate my listOfObjects with the values of my .csv file.
Someone can help me? I'm not really good at Groovy so I'm facing this problem now =//
I think you need to change this line:
vars.put("listOfObjects", "'objectName1', 'objectName2', 'ObjectName3'");
to this one:
vars.put("listOfObjects", '"' + objectNames.join('","') + '"');
and amend your request body to:
{
[ ${listOfObjects} ]
}
More information:
List.join() function
Apache Groovy: What Is Groovy Used For?
I've done this way. I've removed the last elements of the array to remove the end of file
, "
String csvFile = props.get("csvPathAndName")
log.info('__________________________________________________________________________________________________________________________________________________________')
log.info(csvFile)
//function to read csv file
def readLines(String csvFile) {
StringBuilder requestBody = new StringBuilder();
File file = new File(csvFile);
ArrayList<String> objectNames = file.readLines();
objectNames.eachWithIndex {
val, index ->
if (index == 0) {
requestBody.append(val + "\", ")
} else {
requestBody.append("\"" + val + "\", ")
}
}
requestBody.setLength(requestBody.length() -3)
vars.put("listOfObjects", requestBody.toString());
}
readLines(csvFile)
And my request body was just
[${listOfObjects}]
\n54766392632990,178.32.243.13,wfsdsfsdfs23432,\n54766393632990,178.32.243.13,
Above u can see example of string which I want to parse.. I want to get array if numbers which exist between (\n....,178.32.243.13) .. In this example it will be smth like :
[54766392632990,54766393632990] - how to make it
Please run this script it full file your requirement
var ss = "\n54766392632990,178.32.243.13,wfsdsfsdfs23432,\n54766393632990,178.32.243.13,"
var ddd = ss.split(",")
console.log(ddd)
var dfd = []
ddd.forEach(function(res){
if(res.startsWith("\n"))
{
dfd.push(res.replace("\n",""))
}
})
console.log(dfd)
Result [ '54766392632990', '54766393632990' ]
"\n54766392632990,178.32.243.13,wfsdsfsdfs23432,\n54766393632990,178.32.243.13,"
.split("\n")
.filter((n)=> n!== "")
.map(n=> parseInt(n.split(",")[0]))
You can do something like this to parse this string
let s = "\n54766392632990,178.32.243.13,wfsdsfsdfs23432,\n54766393632990,178.32.243.13,"
s = s.split("\n");
let array = [];
for(let i=0;i<s.length;i++) {
let v = s[i].split(",178.32.243.13,");
for(let j=0;j<v.length;j++) {
if(!isNaN(parseInt(v[j]))) {
array.push(v[j]);
}
}
}
console.log(array);
I'm creating a MacOS application that generates dialog files from a tab-delimited text file. The text file is formatted (output filename) [tab] (text to be spoken to that file). I got the program working perfectly running in the main thread, but this blocked the UI, of course. When I moved the meat of the application to a User Initiated thread, I unblocked the UI, but now it occasionally and randomly speaks a line out the speaker instead of to a file. A file is still created, but it's of zero duration. If the script contains 1,000 lines, it might get through the whole thing perfectly, or it might "speak" ten or more of them out the speaker. It's almost always different lines each time.
This is the code that speaks to a file:
// Set URL to save file to disk
if let speechFileURL = NSURL(string: speechFilePath) {
speechSynth.startSpeakingString(spokenText, toURL: speechFileURL) // Speak to file
}
else {
dialogAlert("Invalid File: ", text: speechFileName)
}
while(NSSpeechSynthesizer.isAnyApplicationSpeaking() == true) {
if self.gUserClickedStop {
speechSynth.stopSpeaking()
self.gIsSpeaking = false
break
}
}
This is the call to the function that parses the script and generates the speech files:
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) { [unowned self] in
self.parseTheScript()
}
As mentioned above, calling parseTheScript() without wrapping it in the Grand Central Dispatch call makes it work perfectly, except for the blocking issue.
I'm new to programming in Swift and the idea of multithreaded programming, so I'm sure I'm doing something wrong, but I'm stumped as to how to fix this problem.
Thank you in advance for your help.
Edit to add...
This is the entire function that parses the text file and generates the dialog files:
// This opens the text file and generates the spoken audio files
func parseTheScript() {
let filemgr = NSFileManager.defaultManager()
print("Chosen path: \(scriptFileTextField.stringValue)") // debug
if filemgr.fileExistsAtPath(scriptFileTextField.stringValue) {
print("File exists")
do {
outputFilename.stringValue = ""
scriptToSpeak.stringValue = ""
outputFilename.hidden = false
scriptToSpeak.hidden = false
progressBar.minValue = 0
progressBar.doubleValue = 0.0
progressBar.hidden = false
filenameLabel.hidden = false
let text = try String(contentsOfFile: scriptFileTextField.stringValue, encoding: NSUTF8StringEncoding)
let lines: [String] = text.componentsSeparatedByString("\n")
var progressEndValue = Double(lines.count)
progressBar.maxValue = progressEndValue
let speechSynth = NSSpeechSynthesizer.init()
let theVoice = gVoiceList[voiceListPopup.indexOfSelectedItem - 1] // Not sure why it's off by one
speechSynth.setVoice(theVoice)
for line in lines {
let thisLine: [String] = line.componentsSeparatedByString("\t") // Split the line at the tab character
if (thisLine.count == 2) { // Did the line split into two parts?
let speechFileName = thisLine[0]
let spokenText = thisLine[1]
outputFilename.stringValue = speechFileName
scriptToSpeak.stringValue = spokenText
let speechFilePath = destinationFolderTextField.stringValue + speechFileName + ".aif" // Build the path string for the output speech file
print("Filename: \(speechFilePath)")
print("SpokenText: \(spokenText)")
if(gSpeakToFile) {
// Set URL to save file to disk
if let speechFileURL = NSURL(string: speechFilePath) {
speechSynth.startSpeakingString(spokenText, toURL: speechFileURL) // Speak to file
}
else {
dialogAlert("Invalid File: ", text: speechFileName)
}
}
else {
speechSynth.startSpeakingString(spokenText) // Speak to audio output
}
while(NSSpeechSynthesizer.isAnyApplicationSpeaking() == true) {
if self.gUserClickedStop {
speechSynth.stopSpeaking()
self.gIsSpeaking = false
break
}
}
progressBar.incrementBy(1.0)
}
if gUserClickedStop {
gUserClickedStop = false
gIsSpeaking = false
progressEndValue = 0
generateButton.title = "Start"
break
}
}
gIsSpeaking = false
progressBar.doubleValue = progressEndValue
generateButton.title = "Start"
filenameLabel.hidden = true
outputFilename.stringValue = ""
scriptToSpeak.stringValue = ""
} catch let error as NSError {
dialogAlert("Error:", text: String(error.localizedDescription))
print("Error: \(error)")
}
} else {
print("File does not exist")
}
}
I am looking for a way to replace a word inside a string in swift. Can anyone help?
this is what I have so far, I can find the specific word, but i do not know how to replace it...
var str = "helo, playgound"
var findWords = ["helo","playgound"]
var replaceWords = ["hello","playground"]
extension String {
var wordList:[String] {
return "".join(componentsSeparatedByCharactersInSet(NSCharacterSet.punctuationCharacterSet())).componentsSeparatedByString(" ")
}
}
func stringToArray() -> Array<String> {
var arr = str.wordList
return arr
}
func correction(var _arr:Array<String>) -> String{
for var i = 0; i < _arr.count; i++ {
if str.lowercaseString.rangeOfString(findWords[i]) != nil {
println("exists")
}
}
return str
}
It depends what your definition of a "word" is. If you're looking for an intelligent built-in notion of a "word", the easiest solution is probably to use NSRegularExpression, which knows where "word" boundaries are:
var s = NSMutableString(string:"hello world, go to hell")
let r = NSRegularExpression(
pattern: "\\bhell\\b",
options: .CaseInsensitive, error: nil)!
r.replaceMatchesInString(
s, options: nil, range: NSMakeRange(0,s.length),
withTemplate: "heaven")
After that, s is "hello world, go to heaven", which is the right answer; we replaced the "hell" that is a word, but not the "hell" in "hello". Notice that we are also matching case-insensitively, which seems to be one of your desiderata.
That example shows how do just one pair ("hell" and "heaven") but it is easy to abstract it into a method so that you can do it again and again for further pairs:
var str = "helo, playgound"
var findWords = ["helo", "playgound"]
var replaceWords = ["hello", "playground"]
func correct(str:String, orig:String, repl:String) -> String {
var s = NSMutableString(string:str)
let r = NSRegularExpression(
pattern: "\\b\(orig)\\b",
options: .CaseInsensitive, error: nil)!
r.replaceMatchesInString(
s, options: nil, range: NSMakeRange(0,s.length),
withTemplate: repl)
return s
}
for pair in Zip2(findWords,replaceWords) {
str = correct(str, pair.0, pair.1)
}
str // hello, playground
The easiest is probably this:
let statement = "Swift is hard."
let swiftRange = statement.startIndex..<advance(statement.startIndex, 5)
let newStatement = statement.stringByReplacingCharactersInRange(swiftRange, withString: "Objective-C")
// now newStatement = "Objective-C is hard."
Following a longer commenting tour: The above is under the assumption of the OP "I can find the specific word, but i do not know how to replace it...", so it's not about finding a "word" which to define is another discussion. It's just about replacing an already found word.
Another word on stringByReplacingCharactersInRange: #matt states that this is Cocoa cross-over. In that case Apple is telling a plain lie:
I fostered the web but there's no Apple source telling anything. Only the Foundation method for NSString. Their Swift book is silent too (in many respects). Well, I don't trust Apple anyway any longer since Yosemite-fail.