How to fetch safety value from String in Swift iOS? - ios

I have EKParticipant object with description looks like:
item description: EKAttendee <0x1c0b7d90> {UUID = 116B99AB9-41AC-4741-A288-B67172298625; name = Snaggy Snags; email = snaggy#gmail.com; status = 4; role = 1; type = 1}
How to safety split this string to Dictionary in order to fetch after email key value?
This is what I did so far:
extension String {
func split(splitter: String) -> Array<String> {
let regEx = NSRegularExpression(pattern: splitter, options: NSRegularExpressionOptions(), error: nil)!
let stop = "SomeStringThatYouDoNotExpectToOccurInSelf"
let modifiedString = regEx.stringByReplacingMatchesInString(self, options: NSMatchingOptions(), range: NSMakeRange(0, countElements(self)), withTemplate: stop)
return modifiedString.componentsSeparatedByString(stop)
}
func removeCharsFromEnd(count:Int) -> String{
let stringLength = countElements(self)
let substringIndex = (stringLength < count) ? 0 : stringLength - count
return self.substringToIndex(advance(self.startIndex, substringIndex))
}
}
var str = "item description: EKAttendee <0x1c0b7d90> {UUID = 16B99AB9-41AC-4742-A288-B67172299625; name = Snaggy Snags; email = snaggy#gmail.com; status = 4; role = 1; type = 1}"
var newStr = str.split("\\{")[1]
newStr = newStr.removeCharsFromEnd(1)
So now newStr equals:
UUID = 16B99AB9-41AC-4741-A288-B67172298625; name = Snaggy Snags; email = snaggy#gmail.com; status = 4; role = 1; type = 1
What next?
Thanks,

You can use componentsSeparatedByString method to extract your elements as follow:
extension String {
var elements:(udid: String, name: String, email: String, status: Int, role: Int, type: Int) {
let components = componentsSeparatedByString("; ")
if components.count == 6 {
let udid = components[0].componentsSeparatedByString(" = ").last ?? ""
let name = components[1].componentsSeparatedByString(" = ").last ?? ""
let email = components[2].componentsSeparatedByString(" = ").last ?? ""
let status = components[3].componentsSeparatedByString(" = ").last ?? ""
let role = components[4].componentsSeparatedByString(" = ").last ?? ""
let type = components[5].componentsSeparatedByString(" = ").last ?? ""
return (udid, name, email, (status as NSString).integerValue, (role as NSString).integerValue, (type as NSString).integerValue)
}
return ("","","",0,0,0)
}
}
let input = "UUID = 16B99AB9-41AC-4741-A288-B67172298625; name = Snaggy Snags; email = snaggy#gmail.com; status = 4; role = 1; type = 1"
let result = input.elements // (.0 "16B99AB9-41AC-4741-A288-B67172298625", .1 "Snaggy Snags", .2 "snaggy#gmail.com", .3 4, .4 1, .5 1, .6 "UUID = 16B99AB9-41AC-4741-A288-B67172298625; name = Snaggy Snags; email = snaggy#gmail.com; status = 4; role = 1; type = 1")
println(result.udid) // "16B99AB9-41AC-4741-A288-B67172298625"
println(result.name) // "Snaggy Snags"
println(result.email) // "snaggy#gmail.com"
println(result.status.description) // "4"
println(result.role.description) // "1"
println(result.type.description) // "1"
You can also use String's method hasPrefix to make sure you are grabbing the right info from your elements even if they return unordered as follow:
extension String {
var elements:(udid: String, name: String, email: String, status: Int, role: Int, type: Int) {
let components = componentsSeparatedByString("; ")
var udid = "", name = "", email = "", status = 0, role = 0, type = 0
for item in components {
println(item)
if item.hasPrefix("UUID = "){
udid = item.substringWithRange(Range(start: advance(item.startIndex, 7), end: item.endIndex))
}
if item.hasPrefix("name = "){
name = item.substringWithRange(Range(start: advance(item.startIndex, 7), end: item.endIndex))
}
if item.hasPrefix("email = "){
email = item.substringWithRange(Range(start: advance(item.startIndex, 8), end: item.endIndex))
}
if item.hasPrefix("status = "){
status = (item.substringWithRange(Range(start: advance(item.startIndex, 9), end: item.endIndex)) as NSString).integerValue
}
if item.hasPrefix("role = "){
role = (item.substringWithRange(Range(start: advance(item.startIndex, 7), end: item.endIndex)) as NSString).integerValue
}
if item.hasPrefix("type = "){
type = (item.substringWithRange(Range(start: advance(item.startIndex, 7), end: item.endIndex)) as NSString).integerValue
}
}
return (udid, name, email, status, role, type)
}
}
let input = "UUID = 16B99AB9-41AC-4741-A288-B67172298625; name = Snaggy Snags; email = snaggy#gmail.com; status = 4; role = 1; type = 1"
let elements = input.elements // (.0 "16B99AB9-41AC-4741-A288-B67172298625", .1 "Snaggy Snags", .2 "snaggy#gmail.com", .3 4, .4 1, .5 1)
let udid = elements.udid // "16B99AB9-41AC-4741-A288-B67172298625"
let name = elements.name // "Snaggy Snags"
let email = elements.email // "snaggy#gmail.com"
let status = elements.status.description // "4"
let role = elements.role.description // "1"
let type = elements.type.description // "1"

Here is method that fetches email or returns nil if something goes wrong:
func fetchEmailIfExists(str:String) -> String?{
var email:String?
for item:String in str.split(";"){
if item.contains("email"){
var emailPart = item.trim()
if emailPart.componentsSeparatedByString("=").first?.trim() == "email" {
if let temp:String = emailPart.componentsSeparatedByString("=").last?.trim(){
return temp
}
}
}
}
return email
}
Helpers
extension String {
func split(splitter: String) -> Array<String> {
let regEx = NSRegularExpression(pattern: splitter, options: NSRegularExpressionOptions(), error: nil)!
let stop = "SomeStringThatYouDoNotExpectToOccurInSelf"
let modifiedString = regEx.stringByReplacingMatchesInString(self, options: NSMatchingOptions(), range: NSMakeRange(0, countElements(self)), withTemplate: stop)
return modifiedString.componentsSeparatedByString(stop)
}
func trim() -> String {
return self.stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet())
}
func contains(find: String) -> Bool{
return self.rangeOfString(find) != nil
}
}

This a perfect use case for NSScanner. The stringToDictionary takes a String like yours and returns a dictionary of [String: String]. You can use it for any string in your format, regardless of the amount of key/value pairs. However it will break down when the values contain semicolons or equal signs.
let string = "item description: EKAttendee <0x1c0b7d90> {UUID = 116B99AB9-41AC-4741-A288-B67172298625; name = Snaggy Snags; email = snaggy#gmail.com; status = 4; role = 1; type = 1}"
var dictionary = stringToDictionary(string)
func stringToDictionary(input: String) -> [String: String] {
var output = [String: String]()
let scanner = NSScanner(string: input)
let separatingCharacters = NSCharacterSet(charactersInString: ";}")
scanner.scanUpToString("{", intoString: nil)
scanner.scanString("{", intoString: nil)
var key: NSString?, value: NSString?
while !scanner.atEnd {
scanner.scanUpToString(" =", intoString: &key)
scanner.scanString("= ", intoString: nil)
scanner.scanUpToCharactersFromSet(separatingCharacters, intoString: &value)
scanner.scanCharactersFromSet(separatingCharacters, intoString: nil)
if let key = key as? String, value = value as? String {
output[key] = value
}
}
return output
}

Related

How to integrate PayUMoney in swift

I want to integrate the PayUMoney SDK in my app using
I am using this link to integrate PayUMoney: How to integrate PayU Money in swift
I can see only the option to pay by credit card referring to the link's sample code however it is not showing up the net banking option. I don't understand what I am doing wrong in my code.
Here's what I have tried -
import UIKit
import PlugNPlay
import CommonCrypto
class PaymentVC: UIViewController {
var type = String()
var email = String()
var name = String()
var phone = String()
var address = String()
var state = String()
var zipcode = String()
var officetype = Int()
var TotalAmmount = String()
override func viewDidLoad() {
super.viewDidLoad()
continueWithCardPayment()
// Do any additional setup after loading the view.
}
#IBAction func backButtonAction(_ sender: UIButton) {
self.navigationController?.popViewController(animated: true)
}
func continueWithCardPayment()
{
var paymentParam = PUMTxnParam()
paymentParam.key = "Zegfsgh"
paymentParam.merchantid = "7085776"
paymentParam.txnID = "xyz"
paymentParam.phone = "8770338859"
paymentParam.amount = TotalAmmount
paymentParam.productInfo = "Nokia"
paymentParam.surl = "https://test.payumoney.com/mobileapp/payumoney/success.php"
paymentParam.furl = "https://test.payumoney.com/mobileapp/payumoney/failure.php"
paymentParam.firstname = "john"
paymentParam.email = "john#john.com"
paymentParam.environment = PUMEnvironment.test
paymentParam.udf1 = "udf1"
paymentParam.udf2 = "udf2"
paymentParam.udf3 = "udf3"
paymentParam.udf4 = "udf4"
paymentParam.udf5 = "udf5"
paymentParam.udf6 = ""
paymentParam.udf7 = ""
paymentParam.udf8 = ""
paymentParam.udf9 = ""
paymentParam.udf10 = ""
paymentParam.hashValue = self.getHashForPaymentParams(paymentParam)
// paymentParam. = ""
// Set this property if you want to give offer:
// paymentParam.userCredentials = ""
PlugNPlay.presentPaymentViewController(withTxnParams: paymentParam, on: self, withCompletionBlock: { paymentResponse, error, extraParam in
if error != nil {
UIUtility.toastMessage(onScreen: error?.localizedDescription, from: .none)
} else {
var message = ""
if paymentResponse?["result"] != nil && (paymentResponse?["result"] is [AnyHashable : Any]) {
print(paymentResponse!)
message = "Hello Asad sucess"
// message = paymentResponse?["result"]?["error_Message"] as? String ?? ""
// if message.isEqual(NSNull()) || message.count == 0 || (message == "No Error") {
// message = paymentResponse?["result"]?["status"] as? String ?? ""
// }
} else {
message = paymentResponse?["status"] as? String ?? ""
}
UIUtility.toastMessage(onScreen: message, from: .none)
}
})
PlugNPlay.presentPaymentViewController(withTxnParams: paymentParam, on: self, withCompletionBlock: .none)
}
func sha512(_ str: String) -> String {
let data = str.data(using:.utf8)!
var digest = [UInt8](repeating: 0, count: Int(CC_SHA512_DIGEST_LENGTH))
data.withUnsafeBytes({
_ = CC_SHA512($0, CC_LONG(data.count), &digest)
})
return digest.map({ String(format: "%02hhx", $0) }).joined(separator: "")
}
func getHashForPaymentParams(_ txnParam: PUMTxnParam?) -> String? {
let salt = "vw8LigfjD"
var hashSequence: String? = nil
if let key = txnParam?.key, let txnID = txnParam?.txnID, let amount = txnParam?.amount, let productInfo = txnParam?.productInfo, let firstname = txnParam?.firstname, let email = txnParam?.email, let udf1 = txnParam?.udf1, let udf2 = txnParam?.udf2, let udf3 = txnParam?.udf3, let udf4 = txnParam?.udf4, let udf5 = txnParam?.udf5, let udf6 = txnParam?.udf6, let udf7 = txnParam?.udf7, let udf8 = txnParam?.udf8, let udf9 = txnParam?.udf9, let udf10 = txnParam?.udf10 {
hashSequence = "\(key)|\(txnID)|\(amount)|\(productInfo)|\(firstname)|\(email)|\(udf1)|\(udf2)|\(udf3)|\(udf4)|\(udf5)|\(udf6)|\(udf7)|\(udf8)|\(udf9)|\(udf10)|\(salt)"
}
let hash = self.sha512(hashSequence!).description.replacingOccurrences(of: "<", with: "").replacingOccurrences(of: ">", with: "").replacingOccurrences(of: " ", with: "")
return hash
}
func paymentResponseReceived(notify:NSNotification) {
print(notify)
}
}

How to replace Email id text before # with * in swift 3.0

Hello I have not get perfect solution for how to replace Email Id text before # with * like
suppose my email id is XXXXXXX#gmail.com then my output I want like *******#gmail.com
I try like this
let delimiter = "#"
let newstr = "Himmoradiya#gmail.com"
var token = newstr.components(separatedBy: delimiter)
let newQuery = (token[0] as NSString).replacingCharacters(
in: NSMakeRange(0,token[0].characters.count), with: "*")
Any suggestion is accepted.
Thank you.
Use init(repeating:count:)
let newstr = "Himmoradiya#gmail.com"
var token = newstr.components(separatedBy: "#")
let newQuery = String(repeating: "*", count: token[0].characters.count) //check array length before using index
print(newQuery + "#" + token[1] ) // *******#gmail.com
Write this code:
let aString = "This is my string"
let newString = aString.replacingOccurrences(of: "#", with: "*")
Use this function .
func getStarred(_ email : String ) -> String
{
var didFoundATRO = false
var tempString = ""
for char in email.characters
{
if char == "#"
{
didFoundATRO = true
}
if !didFoundATRO
{
tempString += "*"
}
else
{
tempString.append(char)
}
}
return tempString
}
You can do like,
let delimiter = "#"
let newstr = "Himmoradiya#gmail.com"
let arr = newstr.components(separatedBy: delimiter)
let resultStr = "xxxxxx" + "#" + arr[1]
print(resultStr)
let delimiter = "#"
var newstr = "Himmoradiya#gmail.com"
let arr = newstr.components(separatedBy: delimiter)
let strMail = arr.first!
let strReplaceStr = String(repeating: "*", count: strMail.characters.count)
newstr = newstr.replacingOccurrences(of: strMail, with: strReplaceStr)
and output (newstr) will be : ***********#gmail.com
I have created a string extension like...
extension String {
var hideEmailPrefix: String {
if self.contains("#") {
var part = self.components(separatedBy: "#")
let newText = String(repeating: "*", count: part[0].count)
return newText + "#" + part[1]
}
return self
}
}
Then in my ViewController:
override func viewDidLoad() {
super.viewDidLoad()
let email = "abc#gmail.com"
print(email.hideEmailPrefix) // ***#gmail.com
}
var maskEmail: String {
let email = self
let components = email.components(separatedBy: "#")
var maskEmail = ""
if let first = components.first {
maskEmail = String(first.enumerated().map { index, char in
return [0, 1, first.count - 1, first.count - 2].contains(index) ?
char : "*"
})
}
if let last = components.last {
maskEmail = maskEmail + "#" + last
}
return maskEmail
}
var maskPhoneNumber: String {
return String(self.enumerated().map { index, char in
return [0, 3, self.count - 1, self.count - 2].contains(index) ?
char : "*"
})
}

How to check variable value in swift 3?

I would like to check the value of the outgoing variable whether it is 0 or 1. I tried below code to do the same but I am not able to check it. In below code message is a dictionary which contains values of XMPPMessageArchiving_Message_CoreDataObject.
How to check the value of outgoing variable?
message dictionary contains:
bareJid = "(...not nil..)";
bareJidStr = "tester3#90.0.0.163";
body = "{\"Date\":\"14 Jun 2017\",\"Time\":\"4:21PM\",\"body\":\"hello\",\"filePath\":\"\",\"isImportant\":\"N\",\"isMine\":true,\"msgid\":\"167-36\",\"receiver\":\"tester1\",\"sender\":\"tester3\",\"senderName\":\"tester3\"}";
composing = 0;
message = "(...not nil..)";
messageStr = "<message xmlns=\"jabber:client\" to=\"tester1#90.0.0.163\" id=\"167-36\" type=\"chat\" from=\"tester3#90.0.0.163/Smack\"><body>{\"Date\":\"14 Jun 2017\",\"Time\":\"4:21PM\",\"body\":\"hello\",\"filePath\":\"\",\"isImportant\":\"N";
outgoing = 0;
streamBareJidStr = "tester1#90.0.0.163";
thread = "2066797c-4f79-48f3-bd04-30658ee35e9f";
timestamp = "2017-06-14 11:20:41 +0000";
When I debug the value of outgoing variable then Xcode shows the type of it is Any? and value of it is some.
let outgoing = messasge.value(forKey: "outgoing")
var isIncoming = true
if let og = outgoing as? Int {
if og == 1 {
isIncoming = false
}
}
If your dictionary value data type is Anyobject then unwrap as NSNumber and convert to integer or bool
if let outgoing = message["outgoing"] {
let convertedValue = Int(outgoing as! NSNumber)
if convertedValue == 1 {
isIncoming = false
print("Incoming false")
}
}
Example :
var messasge = [String: AnyObject]()
messasge["outgoing"] = "1" as AnyObject;
if let outgoing = messasge["outgoing"] {
let convertedValue = Int(outgoing as! NSNumber)
if convertedValue == 1 {
print("Incoming false")
}
}
message["outgoing"] value data type is String :
var messasge = [String: Any]()
messasge["outgoing"] = "1" ;
if let outgoing = messasge["outgoing"] as? String, outgoing == "1" {
isIncoming = false
}
message["outgoing"] value data type is Int :
var messasge = [String: Any]()
messasge["outgoing"] = 1 ;
if let outgoing = messasge["outgoing"] as? Int, outgoing == 1 {
isIncoming = false
}
let outgoing : String = messasge.value(forKey: "outgoing")
let og = Int(outgoing)
if og == 1
{// isIncoming = false
}
else
{
//isIncoming = true
}

Replace numeric of different length in a string with different text length

Problem: Numeric is of different length could be 1, 200, 1000, 39 99995 etc. And need to replace with a text eg. "Apple" which is of different lenth comapring to the numeric values.
let str: String = "hello i have 1313 object of 10 string class with 1 object, similar to 9999 errors"
Expected Result = "hello i have Apple object of Apple string class with Apple object, similar to Apple errors"
I have tried with below code:
var originalString: String = "hello i have 1313 object of 10 string class with 1 object, similar to 9999 errors"
let strippedString: NSMutableString = NSMutableString(capacity: originalString.characters.count)
var numArray: [String] = []
var locArray: [NSNumber] = []
var scanner: NSScanner = NSScanner(string:originalString)
let numbers: NSCharacterSet = NSCharacterSet(charactersInString: "0123456789")
while scanner.atEnd == false {
var buffer: NSString?
if scanner.scanCharactersFromSet(numbers, intoString: &buffer) {
strippedString.appendString(buffer! as String)
numArray.append(buffer! as String)
locArray.append(scanner.scanLocation)
}
else {
scanner.scanLocation = (scanner.scanLocation + 1)
}
}
for (index, _) in numArray.enumerate() {
var loc : Int = Int(locArray[index] ) - (String(numArray[index]).characters.count)
let len = String(numArray[index]).characters.count
let dupStr = "Apple"
if(index != 0 && len != dupStr.characters.count)
{
loc = loc + (dupStr.characters.count - len) + 1
}
originalString.replaceRange(originalString.startIndex.advancedBy(loc)..<originalString.startIndex.advancedBy(loc + len), with: dupStr)
}
print(originalString)
Swift 2
NSScanner is great, but if you want a simpler solution for this task, you could use componentsSeparatedByString, map, Int() and joinWithSeparator, like this:
let originalString = "hello i have 1313 object of 10 string class with 1 object, similar to 9999 errors"
let tokens = originalString.componentsSeparatedByString(" ")
let newTokens = tokens.map { (token) -> String in
if let _ = Int(token) {
return "Apple"
}
return token
}
let result = newTokens.joinWithSeparator(" ")
print(result)
Prints:
hello i have Apple object of Apple string class with Apple object, similar to Apple errors
There's also a short version for the mapping:
let newTokens = tokens.map { Int($0) != nil ? "Apple" : $0 }
Swift 3
componentsSeparatedByString(_:) is now components(separatedBy:), and joinWithSeparator(_:) is now joined(separator:).
let tokens = originalString.components(separatedBy: " ")
let newTokens = tokens.map { Int($0) != nil ? "Apple" : $0 }
let result = newTokens.joined(separator: " ")
var str: String = "hello i have 1313 object of 10 string class with 1 object, similar to 9999 errors"
var comp: [AnyObject] = [AnyObject](array: str.componentsSeparatedByString(" "))
for var i = 0; i < comp.count; i++ {
var numberRegex: NSRegularExpression = NSRegularExpression.regularExpressionWithPattern("^[0-9]", options: NSRegularExpressionCaseInsensitive, error: nil)
var regexMatch: Int = numberRegex.numberOfMatchesInString(comp[i], options: 0, range: NSMakeRange(0, (String(comp[i])).length))
if regexMatch != 0 {
comp[i] = "Apple"
}
}
var result: String = comp.componentsJoinedByString(" ")
print(result)

Save data from textfile in a array and/or dictionary

I hang on a programming step. I hope you can help me.
I got in a textfile the following rows:
#Objekt
Objektnr; 1000000;
Filialname; Dresden;
Filialeemail; email#email.com;
#Baustelle
Anschrift1;;
Anschrift2;Juwelier Schubert;
Strasse;Theresienstrafle 7;
Land;DE;
Ort;TheTown;
PLZ;12345;
....
I have the following function for bring the file-data to an array or an dictionary. In another function i will save the data to the local CoreData-Database.
func startImportTextfile(fileName: String, fileDir: String) -> Bool {
var filePath : String = folderDocuments.stringByAppendingPathComponent(fileDir)
var fileNameWithPath = filePath.stringByAppendingPathComponent(fileName)
var fullImportContent = String(contentsOfFile: fileNameWithPath, encoding: NSUTF8StringEncoding, error: nil)
if(fullImportContent != "")
{
var stringArray = fullImportContent!.componentsSeparatedByString("\n")
var stringArrayCompleteData = Dictionary<String, Array<Any>>()
var arrIndexSection : String = "NoHeader"
for singleRow in stringArray
{
if(singleRow != "")
{
switch singleRow {
case "#Header":
arrIndexSection = singleRow.stringByReplacingOccurrencesOfString("#", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
case "#Objekt":
arrIndexSection = singleRow.stringByReplacingOccurrencesOfString("#", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
case "#Baustelle":
arrIndexSection = singleRow.stringByReplacingOccurrencesOfString("#", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
case "#Auftraggeber":
arrIndexSection = singleRow.stringByReplacingOccurrencesOfString("#", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
case "#Architekt":
arrIndexSection = singleRow.stringByReplacingOccurrencesOfString("#", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
case "#Vermittler":
arrIndexSection = singleRow.stringByReplacingOccurrencesOfString("#", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
case "#Regulierer":
arrIndexSection = singleRow.stringByReplacingOccurrencesOfString("#", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
case "#Versicherung":
arrIndexSection = singleRow.stringByReplacingOccurrencesOfString("#", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
case "#Kontaktstellen":
arrIndexSection = singleRow.stringByReplacingOccurrencesOfString("#", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
case "#Dateien":
arrIndexSection = singleRow.stringByReplacingOccurrencesOfString("#", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
default:
//Here the multiple array would be filled
var arrSingleRow = singleRow.componentsSeparatedByString(";")
if( arrSingleRow.count > 0 )
{
if( arrIndexSection == "Kontaktstellen" )
{
//TODO: Kontaktstellen einlesen
//#Kontaktstellen
//Baustelle;0;348873;;;;0
//Baustelle;0;381263;;Albrecht;0815;0
//Regulierer/SV;0;171979;Josef;Eder;08546/911055;0
println( "Kontaktstellendaten" )
println( singleRow )
}
else if( arrIndexSection == "Dateien" )
{
//TODO: Dateien einlesen
//#Dateien
//11022015090007_BEmail_INNNUE_21102014141534.pdf; 99; Email an asdfasdf#sdf.de
println( "Dateiendaten" )
println( singleRow )
}
else
{
stringArrayCompleteData[arrIndexSection] = [arrSingleRow[0]: arrSingleRow[1]]
}
}
}
}
}
for key in stringArrayCompleteData {
println("Key: \(key)")
}
return true
}
else
{
return false
}
}
The aim is that I can open the data like this:
println(stringArrayCompleteData["Objekt"].Objektnr)
But I dont know how i have to declare the stringArrayCompleteData.
Maybe i have to change this decleration
var stringArrayCompleteData = Dictionary<String, Array<Any>>()
to
var stringArrayCompleteData = Array<String, Dictionary<String, Any>>()
Thanks for every little help
Hi Roland – My suggestion would be to divide up the text into the different sections and put each into a struct. For example, you would define a Objekt struct that would contain 3 properties: objektnr, filialname, and filialeemail.
You could make a tree of structs, for example, with a root Person struct. The Person struct would contain properties corresponding to an Objekt struct instance, a Bastille struct instance, etc.
Here's some example code to define the structs:
struct Person:Printable {
init() {
}
var objektStruct:Objekt?
var baustelleStruct:Baustelle?
var description:String {
get {
let objektStructDescription = objektStruct != nil ? objektStruct!.description : ""
let baustelleStructDescription = baustelleStruct != nil ? baustelleStruct!.description : ""
return "\(objektStructDescription)\n\n\(baustelleStructDescription)"
}
}
}
struct Objekt:Printable {
var objektnr:Int = 0
var filialname:String = ""
var filialeemail:String = ""
init(text:String) {
// Divide the text into an array of lines
let textLinesArray:[String] = text.componentsSeparatedByString("\n")
// Loop through each line and set the corresponding property
for textLine:String in textLinesArray {
// Separate the components of the line at each ";" character
var components:[String] = textLine.componentsSeparatedByString(";")
components = components.map({ (componentString:String) -> String in
return componentString.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
})
// Get the key and value for the line.
let key:String = components.count > 0 ? components[0] : ""
let value:String = components.count > 1 ? components[1] : ""
// Based on the key, set the appropriate property value
switch key {
case "Objektnr":
if let valueAsInt = value.toInt() {
objektnr = valueAsInt
}
case "Filialname":
filialname = value
case "Filialeemail":
filialeemail = value
default:
break
}
}
}
var description:String {
get {
return "*Objekt*\n Objektnr = \(objektnr)\n Filialname = \(filialname)\n Filialeemail = \(filialeemail)"
}
}
}
struct Baustelle:Printable {
var anschrift1:String = ""
var anschrift2:String = ""
var strasse:String = ""
var land:String = ""
var ort:String = ""
var plz:Int = 0
init(text:String) {
// Divide the text into an array of lines
let textLinesArray:[String] = text.componentsSeparatedByString("\n")
// Loop through each line and set the corresponding property
for textLine:String in textLinesArray {
// Separate the components of the line at each ";" character
var components:[String] = textLine.componentsSeparatedByString(";")
components = components.map({ (componentString:String) -> String in
return componentString.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
})
// Get the key and value for the line.
let key:String = components.count > 0 ? components[0] : ""
let value:String = components.count > 1 ? components[1] : ""
// Based on the key, set the appropriate property value
switch key {
case "Anschrift1":
anschrift1 = value
case "Anschrift2":
anschrift2 = value
case "Strasse":
strasse = value
case "Land":
land = value
case "Ort":
ort = value
case "PLZ":
if let valueAsInt = value.toInt() {
plz = valueAsInt
}
default:
break
}
}
}
var description:String {
get {
return "*Baustelle*\n Anschrift1 = \(anschrift1)\n Anschrift2 = \(anschrift2)\n Strasse = \(strasse)\n Land = \(land)\n Ort = \(ort)\n PLZ = \(plz)"
}
}
}
I wrote the init methods for the Objekt and Baustelle so that the whole text section can be supplied, and the struct takes care of parsing it into the different properties.
Here's some sample code to use the above structs:
let text = String(contentsOfFile: "/Users/markstone/Downloads/textdata.txt")!
// Divide the text at each double newline into multiline sections.
// Eg., the arrayOfTextSections[0] will be the multiline string:
// #Objekt
// Objektnr; 1000000;
// Filialname; Dresden;
// Filialeemail; email#
let arrayOfTextSections = text.componentsSeparatedByString("\n\n")
// Create an empty Person struct instance. We'll fill it in the loop below
var person = Person()
for textSection in arrayOfTextSections {
// For each text section, find out the heading (eg., #Objekt or #Baustelle).
let sectionStringArray = textSection.componentsSeparatedByString("\n")
let sectionHeading = sectionStringArray[0]
switch sectionHeading {
case "#Objekt":
// Create a new instance of the Objekt using the multiline text in this section, and set this instance to the person.objektStruct property.
person.objektStruct = Objekt(text: textSection)
case "#Baustelle":
// Create a new instance of the Baustelle using the multiline text in this section, and set this instance to the person.baustelleStruct property.
person.baustelleStruct = Baustelle(text: textSection)
default:
break
}
}
print(person)
The line print(person) prints the following output:
*Objekt*
Objektnr = 0
Filialname = Dresden
Filialeemail = email#email.com
*Baustelle*
Anschrift1 =
Anschrift2 = Juwelier Schubert
Strasse = Theresienstrafle 7
Land = DE
Ort = TheTown
PLZ = 12345
With this sort of approach, it's quite easy to then turn the struct instances into managed objects for a core data store.
I placed a text file containing your data and saved in a text file in Document's Directory and passed the text filename and the directory path to the function and the functions returns the dictionary with the data into it in dictionary format.
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let fileDirectory : [String] = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as [String]
var fileDir = fileDirectory[0]
var returnedDictionary : Dictionary = self.startImportTextfile("textdata", fileDir: fileDir)
println(returnedDictionary)
var keyDictionary : Dictionary! = returnedDictionary["Objekt"]
println(keyDictionary["Objektnr"] as String!)
}
func startImportTextfile(fileName: String, fileDir: String) -> Dictionary<String,Dictionary<String,String>> {
let fileNameWithPath :String! = fileDir.stringByAppendingPathComponent(fileName)
var err: NSError?
var currentKey : String!
let fullImportContent :String! = String.stringWithContentsOfFile(fileNameWithPath!, encoding: NSUTF8StringEncoding, error: &err)
var dataDictionary = [String : Dictionary <String,String>]()
if(fullImportContent != "")
{
var singleLineArray = fullImportContent!.componentsSeparatedByString("\n")
for singleRow in singleLineArray
{
if(singleRow != "")
{
switch singleRow
{
case "#Header","#Objekt","#Baustelle","#Auftraggeber","#Architekt","#Vermittler","#Regulierer","#Versicherung","#Kontaktstellen","#Dateien":
currentKey = singleRow.stringByReplacingOccurrencesOfString("#", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)
dataDictionary[currentKey] = Dictionary <String,String>()
default:
var arrayForSingleRow = singleRow.componentsSeparatedByString(";")
if( arrayForSingleRow.count > 0 )
{
var sampledict : Dictionary! = dataDictionary[currentKey]
sampledict[arrayForSingleRow[0]] = arrayForSingleRow[1]
dataDictionary[currentKey] = sampledict
}
}
}
}
}
return dataDictionary
}
}
After executing it i get the following output :
[Objekt: [Filialname: Dresden, Objektnr: 1000000, Filialeemail: email#], Baustelle: [PLZ: 12345, Ort: TheTown, Land: DE, Anschrift1: , Strasse: Theresienstrafle 7, Anschrift2: Juwelier Schubert]]
1000000
where Objekt is the key and it contains a dictionary value and from that dictionary you would be able to access Objektnr as i have done in viewDidLoad.
Link to Text file : https://www.dropbox.com/s/oyzbo128zr3jd6h/textdata?dl=0
It looks like your guess is correct and what you mean to declare stringArrayCompleteData as is indeed a dictionary of dictionaries, with Any as the value type for the dictionary. By the way, you can declare that type a bit more neatly as [String: [String:Any]]
Though, do you just want to store the details as strings? Or do you plan to parse numbers as integers? If you want some stronger-typed set of values, as an alternative to using Any as the data type, you might want to look into using an enum with associated values.
Here’s a version of your code that will store up the data records and insert them under the key. This could be neatened up a lot, but also uses a few Swift features you might find useful.
import Foundation
let folderDocuments = "/"
// rather than return true/false, you could return the data as an optional
func startImportTextfile(fileName: String, fileDir: String) -> [String: [String:String]]? {
let filePath: String = folderDocuments.stringByAppendingPathComponent(fileDir)
let fileNameWithPath = filePath.stringByAppendingPathComponent(fileName)
var error: NSError?
let fullImportContent = String(contentsOfFile: fileNameWithPath, encoding: NSUTF8StringEncoding, error: &error)
if let data = fullImportContent where !data.isEmpty {
let stringArray = split(data) { $0 == "\n" }
var completeData: [String: [String:String]] = [:]
var sectionEntries: [String:String] = [:]
var arrIndexSection: String? = nil
for singleRow in stringArray {
// first is an easy and safe way to check if first character
// has a specific value, whilst handling empty strings
if first(singleRow) == "#" {
// insert records from previous section
if let header = arrIndexSection {
completeData[header] = sectionEntries
}
// start a new section
// dropFirst removes the first "#"
arrIndexSection = dropFirst(singleRow)
sectionEntries = [:]
}
else {
let arrSingleRow = split(singleRow) { $0 == ";" }
if( arrSingleRow.count > 0 ) {
switch arrIndexSection {
case .Some("Kontaktstellen"):
//TODO: Kontaktstellen einlesen
println( "Kontaktstellendaten" )
println( singleRow )
case .Some("Dateien"):
//TODO: Dateien einlesen
println( "Dateiendaten" )
println( singleRow )
default:
if let label = first(arrSingleRow) {
sectionEntries[label] = first(dropFirst(arrSingleRow)) ?? ""
}
}
}
}
}
if let header = arrIndexSection {
completeData[header] = sectionEntries
}
return completeData
}
println("fail: \(error)")
return nil
}
if let data = startImportTextfile(Process.arguments[1], Process.arguments[2]) {
for (key,value) in data {
println("Key: \(key)\nData: \(value)")
}
}

Resources