Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // NOTE: This is NOT an example of a good working program! It is an incomplete
- // badly structured program. It is posted here because I'm asking for help with it
- // - not offering it as an example to be followed.
- // This program compiles and executes, but it is less than half implemented.
- // There are comments describing logic which hasn't been written yet.
- // Xcode produces the warning message "This application is modifying the
- // autolayout engine from a background thread, which can lead to engine
- // corruption and weird crashes. This will cause an exception in a future release."
- // The "read a line from the input file, do an HTTP POST, wait for a response,
- // manipulate the data, write a line to the output file, and loop back to read
- // the next input line" loop (which isn't a loop yet) really wants to run
- // synchronously and the only user interface should be "Pause" and "Quit"
- // buttons and a window where the program updates counts of what it has done.
- // The current problems are:
- // 1. I don't know how to make the loop described above run synchronously -
- // that is, after issuing the HTTP POST, waiting for the response and
- // then processing the response as soon as we get it.
- // 2. I can get paths to the input and output files, but I can't read
- from or write to them.
- // 3. I don't know how to set up a window and update the record counts
- displayed there.
- // 4. I don't know how to setup and interact with the "Pause" and "Quit"
- // buttons.
- // AppDelegate.swift
- // Test App
- //
- // Created by David Rosenberg on 5/29/15.
- // Copyright (c) 2015 David Rosenberg. All rights reserved.
- import Cocoa
- // Define global variables
- var debug: Bool = true
- var OutputPathString: String = ""
- var responseString: NSString = ""
- @NSApplicationMain
- class AppDelegate: NSObject, NSApplicationDelegate {
- @IBOutlet weak var window: NSWindow!
- func applicationDidFinishLaunching(aNotification: NSNotification) {
- // Insert code here to initialize your application
- // Initialize application constants
- var err: NSError?
- let suffixes: Set<String> = ["ARTERY", "AVE", "BLVD", "CIR", "CT", "DR", "FRWY", "HWY", "LN", "PARK", "PKWY", "PIKE", "PL", "RD", "ST", "SQ", "TER", "TRL", "WAY"]
- let regex0: NSRegularExpression = NSRegularExpression(pattern: "\\A.*<b>District Representatives:</b>.*href=\"http://www\\.sec\\.state\\.ma\\.us/ele/eledist/con11idx\\.htm#D[1-9]\" target=\"_blank\">(.*?)</a>.*href=\"http://www\\.sec\\.state\\.ma\\.us/ele/eledist/sen11idx\\.htm#[0-9]{0,5}[a-z]{1,20}\" target=\"_blank\">(.*?)</a>.*\"http://www\\.sec\\.state\\.ma\\.us/ele/eledist/reps11idx\\.htm#[a-z]{1,13}[0-9]{0,2}\" target=\"_blank\">(.*?)</a>.*\\z", options: NSRegularExpressionOptions.DotMatchesLineSeparators, error: nil)!
- let regex1: NSRegularExpression = NSRegularExpression(pattern: "<b>District Representatives:</b>", options: NSRegularExpressionOptions.DotMatchesLineSeparators, error: nil)!
- let regex2: NSRegularExpression = NSRegularExpression(pattern: "No records found. Use these tips for better results:", options: NSRegularExpressionOptions.DotMatchesLineSeparators, error: nil)!
- let regex3: NSRegularExpression = NSRegularExpression(pattern: "Your search produced several results.", options: NSRegularExpressionOptions.DotMatchesLineSeparators, error: nil)!
- let regex4: NSRegularExpression = NSRegularExpression(pattern: "Required: enter a street name</li><li>Required: select a city or town, or enter a zip code", options: NSRegularExpressionOptions.DotMatchesLineSeparators, error: nil)!
- let regex5: NSRegularExpression = NSRegularExpression(pattern: "Required: enter a street name", options: NSRegularExpressionOptions.DotMatchesLineSeparators, error: nil)!
- let regex6: NSRegularExpression = NSRegularExpression(pattern: "Required: select a city or town, or enter a zip code", options: NSRegularExpressionOptions.DotMatchesLineSeparators, error: nil)!
- let regex7: NSRegularExpression = NSRegularExpression(pattern: "^^(\\d{4,5}+)[ -]?+\\d*$", options: NSRegularExpressionOptions.DotMatchesLineSeparators, error: nil)!
- let regex8: NSRegularExpression = NSRegularExpression(pattern: "^\\d*$", options: NSRegularExpressionOptions.DotMatchesLineSeparators, error: nil)!
- let cities: Dictionary<String, String> = ["ABINGTON": "1", "ACTON": "2", "ACUSHNET": "3", "ADAMS": "4", "AGAWAM": "5", "ALFORD": "6", "AMESBURY": "7", "AMHERST": "8"]
- let bodyInitial: String = "This isn't the real initial part of the body"
- let bodyCity: String = "&ctl00%24MainContent%24ddlCityTown="
- let bodySuffix: String = "&ctl00%24MainContent%24ddlStreetSuffix="
- let bodyStreet: String = "&ctl00%24MainContent%24txtStreetName="
- let bodyNumber: String = "&ctl00%24MainContent%24txtStreetNo="
- let bodyZip: String = "&ctl00%24MainContent%24txtZip="
- let wdivURL = NSURL(string: "http://NotTheRealDomain.com")
- let request = NSMutableURLRequest(URL:wdivURL!)
- request.HTTPMethod = "POST"
- // request.setValue("en-us", forHTTPHeaderField: "Accept-Language")
- // request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
- // request.setValue("*/*", forHTTPHeaderField: "Accept")
- // request.setValue("gzip, deflate", forHTTPHeaderField: "Accept-Encoding")
- // or
- // request.addValue("en-us", forHTTPHeaderField: "Accept-Language")
- // request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
- // request.addValue("*/*", forHTTPHeaderField: "Accept")
- // request.addValue("gzip, deflate", forHTTPHeaderField: "Accept-Encoding")
- // Declare and initialize application variables
- var session = NSURLSession.sharedSession()
- var InputRecInt: Int = 0
- var SuccessInt: Int = 0
- var EmptyInt: Int = 0
- var SkippedInt: Int = 0
- var ValidatedInt: Int = 0
- var BadInputInt: Int = 0
- var BadLookupInt: Int = 0
- var InputRecStr: String
- var SuccessStr: String
- var EmptyStr: String
- var SkippedStr: String
- var ValidatedStr: String
- var BadInputStr: String
- var BadLookupStr: String
- var congDist: String
- var senDist: String
- var repDist: String
- var comment: String
- var inputTab = [String]()
- var outputRecord: String
- var inputRecordForWriting: String
- var fatal: Bool // A fatal issue was noted
- var issue: Bool // a non-fatal issue was noted
- var myAlert:NSAlert = NSAlert()
- // Get input file
- var openPanel = NSOpenPanel()
- openPanel.prompt = "Input"
- openPanel.allowsMultipleSelection = false
- openPanel.canChooseDirectories = false
- openPanel.canCreateDirectories = false
- openPanel.canChooseFiles = true
- openPanel.title = "Select the (tab-delimited) input file"
- var openResult = openPanel.runModal()
- // If user cancels, terminate program
- if openResult == NSFileHandlingPanelCancelButton {
- NSApplication.sharedApplication().terminate(0)
- }
- //If we got here, the user must have selected a file
- let InputPathString: String = openPanel.URL!.absoluteString!
- let inFile: NSFileHandle? = NSFileHandle(forReadingAtPath: InputPathString)
- if inFile == nil {
- println("Couldn't open input file at \(InputPathString)")
- } else {
- inFile?.closeFile()
- }
- let InputFilename = openPanel.URL!.lastPathComponent!
- // Get output file
- var samefile: Bool
- do {
- var savePanel = NSSavePanel()
- savePanel.canCreateDirectories = true
- savePanel.prompt = "Output"
- savePanel.title = "Select the output file to be written"
- savePanel.nameFieldStringValue = InputFilename + ".output"
- savePanel.directoryURL = openPanel.URL
- // myAlert.messageText = "openPanel.URL is \(openPanel.URL)"
- // myAlert.runModal()
- // myAlert.messageText = "savePanel.directoryURL is \(savePanel.directoryURL)\nsavePanel.nameFieldStringValue is \(savePanel.nameFieldStringValue)"
- // myAlert.runModal()
- var saveResult = savePanel.runModal()
- // myAlert.messageText = "Output file name is \(savePanel.URL)"
- // myAlert.runModal()
- // If user cancels, terminate program
- if saveResult == NSFileHandlingPanelCancelButton {
- NSApplication.sharedApplication().terminate(0)
- }
- //If we got here, the user must have selected a file
- OutputPathString = savePanel.URL!.absoluteString!
- samefile = OutputPathString.uppercaseString == InputPathString.uppercaseString
- myAlert.messageText = "OutputPathString is \(OutputPathString)\nInputPathString is \(InputPathString)\nsamefile is \(samefile )"
- myAlert.runModal()
- if samefile {
- myAlert.messageText = "The output may NOT be written to the input file. Please select a different output file."
- myAlert.runModal()
- }
- } while samefile
- NSFileManager.defaultManager().createFileAtPath(OutputPathString, contents: NSData(), attributes: nil)
- let outFile: NSFileHandle? = NSFileHandle(forWritingAtPath: OutputPathString)
- if outFile == nil {
- println("Couldn't open output file")
- } else {
- println("Output file looks OK")
- }
- // Set up display window
- // Read a line from the input file
- // While not at EOF
- // Set up display window
- // Read a line from the input file into inputRecord
- // While not at EOF
- var inputRecord: String = ""
- inputRecordForWriting = inputRecord
- ProcessARecord: do {
- // Increment input record count
- ++InputRecInt
- // initialize per record variables
- fatal = false
- issue = false
- congDist = ""
- senDist = ""
- repDist = ""
- comment = ""
- inputTab = [String]()
- outputRecord = ""
- // If input record is empty, write out "Failure, Input, Input record was empty", increment empty counter, and "Break ProcessARecord"
- if inputRecord.isEmpty {
- fatal = true
- congDist = "Failure"
- senDist = "Input"
- repDist = "Input record was empty"
- // comment =
- ++EmptyInt
- break ProcessARecord
- }
- // Store the input record in the inputTab array
- inputTab = inputRecord.componentsSeparatedByString("\t")
- // inputTab[0] is WDIV Skip Flag
- // inputTab[1] is WDIV Street Number
- // inputTab[2] is WDIV Street Name
- // inputTab[3] is WDIV Street Suffix
- // inputTab[4] is WDIV City/Town
- // inputTab[5] is ZIP
- // inputTab[6] is State
- var arrayCount: Int = inputTab.count
- // If input array has fewer than seven elements, add enough empty elements,
- // so that it has seven elements
- for var index = arrayCount; index < 7; ++index {
- inputTab.append("")
- }
- // For each element of the first seven elements of the array, trim leading and trailing whitespace and make it uppercase
- for index in 0...6 {
- inputTab[index] = inputTab[index].stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
- inputTab[index] = inputTab[index].uppercaseString
- }
- // If inputTab[0] (1st input field) is "S", write out "Skipped", increment skipped counter, and "Break ProcessARecord"
- if inputTab[0] == "S" {
- fatal = true
- congDist = "Skipped"
- // senDist =
- // repDist =
- // comment =
- ++SkippedInt
- break ProcessARecord
- }
- // If InputRec[6] is not empty & is not "MA", note (in problem flags) that the state is not MA, set Fatal = true
- if !inputTab[6].isEmpty && inputTab[6] != "MA" {
- fatal = true
- if !comment.isEmpty {
- comment += "; "
- }
- comment += "The state isn't Massachusetts"
- if inputTab[0] != "L" {
- congDist = "Not MA"
- // senDist =
- // repDist =
- // comment =
- ++SkippedInt
- break ProcessARecord
- }
- }
- // StreetNumber = InputRec[1] (2nd input field)
- if regex8.rangeOfFirstMatchInString(inputTab[1] as String, options: NSMatchingOptions.allZeros, range: NSMakeRange(0, count(inputTab[1]))).location == NSNotFound {
- fatal = true
- if !comment.isEmpty {
- comment += "; "
- }
- comment += "Street number must be numeric (or null)"
- }
- if inputTab[1].isEmpty {
- issue = true
- if !comment.isEmpty {
- comment += "; "
- }
- comment += "There is no street number"
- }
- // StreetName = InputRec[2] (3rd input field)
- if inputTab[2].isEmpty {
- fatal = true
- if !comment.isEmpty {
- comment += "; "
- }
- comment += "A street name is required"
- }
- // Percent-Escape StreetName
- var street1 = inputTab[2].stringByReplacingOccurrencesOfString("%", withString: "%25", options: NSStringCompareOptions.LiteralSearch, range: nil)
- var street2 = street1.stringByReplacingOccurrencesOfString("&", withString: "%26", options: NSStringCompareOptions.LiteralSearch, range: nil)
- street1 = street2.stringByReplacingOccurrencesOfString("'", withString: "%27", options: NSStringCompareOptions.LiteralSearch, range: nil)
- street2 = street1.stringByReplacingOccurrencesOfString("+", withString: "%2B", options: NSStringCompareOptions.LiteralSearch, range: nil)
- street1 = street2.stringByReplacingOccurrencesOfString("/", withString: "%2F", options: NSStringCompareOptions.LiteralSearch, range: nil)
- inputTab[2] = street1.stringByReplacingOccurrencesOfString("=", withString: "%3D", options: NSStringCompareOptions.LiteralSearch, range: nil)
- // StreetSuffix = InputRec[3] (4th input field)
- // Test that a suffix is in the set of valid suffixes
- if !inputTab[3].isEmpty && !suffixes.contains(inputTab[3]) {
- fatal = true
- if !comment.isEmpty {
- comment += "; "
- }
- comment += "\(inputTab[3]) is not a valid street suffix"
- }
- // if InputRec[4] (5th input field) is empty, CityTown = "-1"
- if inputTab[4].isEmpty {
- issue = true
- if !comment.isEmpty {
- comment += "; "
- }
- comment += "There is no town/city"
- inputTab[4] = "-1"
- } else {
- // Test that a city is in the dictionary of valid cities
- if var CityNumber = cities[inputTab[4]] {
- inputTab[4] = CityNumber
- } else {
- issue = true
- if !comment.isEmpty {
- comment += "; "
- }
- comment += "\(inputTab[4]) is not a valid city/town"
- inputTab[4] = "-1"
- }
- }
- if inputTab[5].isEmpty {
- issue = true
- if !comment.isEmpty {
- comment += "; "
- }
- comment += "There is no ZIP Code"
- } else {
- // Now for some regular expression fun with the ZIP code
- // Remove a space or hypen and any digits following it from InputRec[5]
- // if InputRec[5] is fewer than four characters, is more than five characters, or
- // contains any non-digits, note (in problem flags) that the ZIP code is invalid
- // if InputRec[5] is exactly four characters, prepend a leading zero
- var newZIP: String = ""
- if regex7.rangeOfFirstMatchInString(inputTab[5] as String, options: NSMatchingOptions.allZeros, range: NSMakeRange(0, count(inputTab[5]))).location == NSNotFound {
- issue = true
- inputTab[5] = ""
- if !comment.isEmpty {
- comment += "; "
- }
- comment += "The ZIP Code is invalid"
- } else {
- newZIP = regex7.stringByReplacingMatchesInString(inputTab[5], options: NSMatchingOptions.allZeros, range: NSMakeRange(0, count(inputTab[5])), withTemplate: "$1")
- if count(newZIP) == 4 {
- inputTab[5] = "0" + newZIP
- } else {
- inputTab[5] = newZIP
- }
- }
- }
- // If CityTown == "-1" and ZIPcode is empty, set Fatal = true
- if inputTab[4] == "-1" && inputTab[5].isEmpty {
- fatal = true
- if !comment.isEmpty {
- comment += "; "
- }
- comment += "Either a city/town or a ZIP code is required"
- }
- // If InputRec[0] is "I", we're done
- if inputTab[0] == "I" {
- if fatal {
- congDist = "Failure"
- senDist = "Input"
- repDist = "See comments"
- // comment =
- ++BadInputInt
- } else if issue {
- congDist = "Checked"
- senDist = "Some non-fatal issue(s)"
- repDist = "See comments"
- // comment =
- ++ValidatedInt
- } else {
- congDist = "Checked"
- senDist = "No issues"
- repDist = "Congratulations"
- // comment =
- ++ValidatedInt
- }
- break ProcessARecord
- }
- // If (Fatal = false or InputRec[0] is "L"), we will do a lookup on the web site
- if inputTab[0] != "L" && fatal {
- congDist = "Failure"
- senDist = "Input"
- repDist = "See comments"
- // comment =
- break ProcessARecord
- }
- // Now we are actually going to do an HTTP POST
- // Assemble HTTP POST
- var bodyData: String = bodyInitial + bodyCity + inputTab[4] + bodySuffix + inputTab[3] + bodyStreet + inputTab[2] + bodyNumber + inputTab[1] + bodyZip + inputTab[5]
- request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
- // Execute HTTP POST
- let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {data, response, error in
- if error != nil {
- println("error=\(error)")
- return
- }
- // Get the response to the HTTP POST
- var responseString = NSString(data: data, encoding: NSUTF8StringEncoding)!
- outFile?.writeData(responseString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!)
- outFile?.closeFile()
- if regex1.rangeOfFirstMatchInString(responseString as String, options: NSMatchingOptions.allZeros, range: NSMakeRange(0, responseString.length)).location != NSNotFound {
- println("Districts exist")
- var results: String = regex0.stringByReplacingMatchesInString(responseString as String, options: NSMatchingOptions.allZeros, range: NSMakeRange(0, responseString.length), withTemplate: "$1\t$2\t$3")
- var resultsTab: [String] = results.componentsSeparatedByString("\t")
- congDist = resultsTab[0]
- senDist = resultsTab[1]
- repDist = resultsTab[2]
- ++SuccessInt
- // myAlert.messageText = results
- // myAlert.runModal()
- // Logically, we want to break out of the ProcessARecord block
- // here. But we can't because we are in a separate task.
- // Fortunately, just exiting this if "else" chain will finish
- // this task and be the equivalent of breaking out of the
- // ProcessARecord block.
- // break ProcessARecord
- } else if regex2.rangeOfFirstMatchInString(responseString as String, options: NSMatchingOptions.allZeros, range: NSMakeRange(0, responseString.length)).location != NSNotFound {
- congDist = "Failure"
- senDist = "Lookup"
- repDist = "No records found"
- ++BadLookupInt
- } else if regex3.rangeOfFirstMatchInString(responseString as String, options: NSMatchingOptions.allZeros, range: NSMakeRange(0, responseString.length)).location != NSNotFound {
- congDist = "Failure"
- senDist = "Lookup"
- repDist = "Ambiguous results"
- ++BadLookupInt
- } else if regex4.rangeOfFirstMatchInString(responseString as String, options: NSMatchingOptions.allZeros, range: NSMakeRange(0, responseString.length)).location != NSNotFound {
- congDist = "Failure"
- senDist = "Lookup"
- repDist = "No street, city/town or ZIP code"
- ++BadLookupInt
- } else if regex5.rangeOfFirstMatchInString(responseString as String, options: NSMatchingOptions.allZeros, range: NSMakeRange(0, responseString.length)).location != NSNotFound {
- congDist = "Failure"
- senDist = "Lookup"
- repDist = "No street name"
- ++BadLookupInt
- } else if regex6.rangeOfFirstMatchInString(responseString as String, options: NSMatchingOptions.allZeros, range: NSMakeRange(0, responseString.length)).location != NSNotFound {
- congDist = "Failure"
- senDist = "Lookup"
- repDist = "No city/town or ZIP code"
- ++BadLookupInt
- } else {
- congDist = "Failure"
- senDist = "Lookup"
- repDist = "Unexpected response from web server"
- ++BadLookupInt
- myAlert.messageText = "The web site gave an unexpected response for line \(InputRecInt) in the input file. Please give a programmer this message (including the line number) and a copy of the input file."
- myAlert.runModal()
- } // End of test to see if we got districts
- } // End of definition of task
- task.resume()
- } while false // End of ProcessARecord block
- // NOTE: In every case where an output record is being written, it is four leading fields followed by the entire input record.
- // Only for debugging purposes, write out the filelds that we sent (or could
- // have sent) to the web site at the beginning of the output record
- if debug && !inputRecord.isEmpty {
- outputRecord = inputTab[1] + "\t" + inputTab[2] + "\t" + inputTab[3] + "\t" + inputTab[4] + "\t" + inputTab[5] + "\t"
- } else {
- outputRecord = ""
- }
- // Write CongDist, SenDist, RepDist, Comment, followed by the input record to the output record
- outputRecord += congDist + "\t" + senDist + "\t" + repDist + "\t" + comment
- if !inputRecordForWriting.isEmpty { outputRecord += "\t" + inputRecordForWriting }
- // Update numbers being displayed
- // if Pause button clicked {
- // Change Pause button to Resume button
- // While Resume not clicked and Quit not clicked {
- // Wait one second
- // }
- // If Quit was clicked {
- // Close output file
- // Close input file
- // Terminate application
- // }
- // // If we got here, Resume must have been clicked
- // Change Resume button back to Pause button
- // }
- // if Quit button clicked {
- // Close output file
- // Close input file
- // Terminate application
- // }
- // Read a line from the input file
- // End of While loop that processes the input file
- // Close output file
- // Close input file
- // Remove Pause button
- // Change Quit button to Finish button
- // While Finish not clicked {
- // Wait one second
- // }
- if false {
- // If we need to show the results in an Alert dialog
- InputRecStr = String(format:"%06d", InputRecInt)
- SuccessStr = String(format:"%06d", SuccessInt)
- EmptyStr = String(format:"%06d", EmptyInt)
- SkippedStr = String(format:"%06d", SkippedInt)
- ValidatedStr = String(format:"%06d", ValidatedInt)
- BadInputStr = String(format:"%06d", BadInputInt)
- BadLookupStr = String(format:"%06d", BadLookupInt)
- var finalResult:NSAlert = NSAlert()
- finalResult.messageText = " Input records: \(InputRecStr)\n Successes: \(SuccessStr)\n Empty records: \(EmptyStr)\nSkipped records: \(SkippedStr)\n Only validated: \(ValidatedStr)\n Bad input: \(BadInputStr)\n Bad lookup: \(BadLookupStr)"
- finalResult.runModal()
- } // End of if false around the finaResults alert
- // Terminate application
- // NSApplication.sharedApplication().terminate(0)
- } // End of applicationDidFinishLaunching
- func applicationWillTerminate(aNotification: NSNotification) {
- // Insert code here to tear down your application
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment