how I can get the domain extensions from UITextField? - swift

I want to accept the users who're studying at University, so I need to only accept the email format as
studentname#inst**.edu** or
studentname#inst**.edu.tr**
how can I verify that by using regex or another method in Swift 5? Thx.

extension String {
func regex(_ regex: String) -> Bool {
return self.range(of: regex, options: .regularExpression) != nil
}
}
let email = "blah_email#inst.edu"
email.regex(#"^[\w]+#inst\.edu$"#)
// If email is of the form: "(...)#inst.edu", it will return true

Related

How to convert the email body to something readable?

Iam working on a simple Apple mailkit extension but cant get something readable out of my mails.
func allowMessageSendForSession(_ session: MEComposeSession, completion: #escaping (Error?) -> Void) {
let mailMessage = session.mailMessage;
let subject = mailMessage.subject
let sender = mailMessage.fromAddress.addressString ?? "undefined";
let data = String(data: mailMessage.rawData!, encoding: .utf8)
In data is the header and the mail body. But its filled with so many 'quoted-printable' strings.
Something like this Viele Gr=C3=BC=C3=\n=9Fe =F0=9F=A4=9D. It should be Viele Grüße 🤝.
I already tried the code in this answer https://stackoverflow.com/a/32827598/1407823 but it seems to only work with single words. I cannot get it to work with a whole text.
Is there no built in way to parse text like this?
There is no built-in way to decode the message, you need a RFC822 parser for example MimeParser on GitHub, available as Swift Package.
This is an example how to decode the body as plain text, messageData represents the raw data of the message
import MimeParser
do {
let messageString = String(data: messageData, encoding: .utf8)!
let parser = MimeParser()
let mime = try parser.parse(messageString)
switch mime.content {
case .body(let body): print(body.raw)
case .alternative(let mimes), .mixed(let mimes):
if let plainTextMime = mimes.first(where: {$0.header.contentType?.subtype == "plain"}),
let decodedBody = try plainTextMime.decodedContentString() {
print(decodedBody)
}
}
} catch {
print(error)
}
With subtype == "html" you get the HTML text, if available

I am trying to validate an email field using Regex in Swift

I am simply trying to validate an email using an expression. I have created a Struct that I use for my form fields.
let emailRegEx = "[A-ZO-9a-z._%+-]+#[A-Za-zO-9.-J+|l.[A-Za-z]{2,64}"
var isEmailValid: Bool {
!email.isEmpty &&
if email.ranges(of: emailRegEx, options: .regularExpression) == nil {
return self
}
}
It keeps throwing this error...Cannot infer contextual base in reference to member 'regularExpression', and Expected expression after operator, lastly Extra argument 'options' in call.
Your if is in the wrong place, and .ranges should be .range.
Assuming your emailRegEx is correct, try this:
var isEmailValid: Bool = !email.isEmpty && (email.range(of: emailRegEx, options: .regularExpression) != nil)
Using a computed var, use this:
var isEmailValid: Bool {
!email.isEmpty && (email.range(of: emailRegEx, options: .regularExpression) != nil)
}
You could also try this regex for email:
let emailRegEx = #"^\S+#\S+\.\S+$"#
Or
let emailRegEx = #"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+#[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$"#
See also this SO post: How to validate an e-mail address in swift?

How to specify the type of text in UITextField

I'm trying to determine whether or not a user is entering a proper email address into a UITextField . I'm using this code but am getting the following error message.
func isValidEmail(testStr:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let range = testStr.rangeOfString(emailRegEx, options:.RegularExpressionSearch) // I'm getting the error message here.
let result = range != nil ? true : false
return result
}
#IBAction func logIn(sender: AnyObject) {
let validLogin = isValidEmail(testStr: field.text!)
if validLogin {
print("User entered valid input")
} else {
print("Invalid email address")
}
}
This is the error message I'm getting: "Value of type 'String' has no member 'rangeOfString'"
I think this is because I don't have RegExKitLite installed but I'm not 100% sure. Even so, I tried installing the kit but I couldn't figure out how. I downloaded the file but I can't figure out how to add it in Xcode.
If you are using Swift 3 or later, the lines:
let range = testStr.rangeOfString(emailRegEx, options:.RegularExpressionSearch)
let result = range != nil ? true : false
return result
needs to be:
let range = testStr.range(of: emailRegEx, options: [ .regularExpression ])
return range != nil
None of this needs a third party library.
You probably also want to make sure the whole string matches so you should add ^ to the start of the regular expression and add $ to the end.

Dynamically filter swift command line input

I'm trying to create a command line app using Swift Package Manager which get some data from user and make something with it. Sounds simple, huh?
func handleInput() {
if let username = requestEnterUserName(), !username.isEmpty {
print("You entered valid username: \(username)")
} else {
handleInput()
}
}
func requestUserName() -> String? {
print("Please enter username: ", terminator: "")
let username = readLine()
let trimmedUserName = username.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
return trimmedUserName
}
My problem is that I don't need backspace characters in username, or whitespace in the middle of it. I would like to filter it dynamically. To delete wrong character after user wrote it. I wonder if it is possible at all.

AppleWatch Messages URL works hard coded but not with variables

TLDR When I hard code phone numbers into a URL it opens in watch messages correctly, but when I use a variable string with the numbers typed in exactly the same way inside of it, it doesn't.
Example:
NSURL(string: "sms:/open?addresses=8888888888,9999999999,3333333333&body=Test")
Above code works but below code doesn't:
let hardCode = "8888888888,9999999999,3333333333"
NSURL(string: "sms:/open?addresses=\(hardCode)&body=Test")
FULL DETAILS:
I am making a URL from variables to open messages on the Apple Watch with pre-filled contents. I am getting the phone numbers from the contact book and storing them in an array. They are provided in this format:
(###) ###-#### but need to be ##########
I tested the code by hard-coding phone numbers into the URL and it works properly with all contacts and completed body:
if let urlSafeBody = urlSafeBody, url = NSURL(string: "sms:/open?addresses=8888888888,9999999999,3333333333&body=\(urlSafeBody)") {
print("FINAL URL: \(url)")
WKExtension.sharedExtension().openSystemURL(url)
}
But when I build the phone number values programmatically it does not work:
//holds phone numbers without special chars
var tempArray: [String] = []
//if I can access the unformatted numbers
if let recips = saveData["recips"] as? [String] {
//for each number provided
recips.forEach { (person: String) in
//remove all non-numerical digits
//person is now (###) ###-####
let newPerson = person.digitsOnly()
//newPerson is ##########
print(person)
print("->\(newPerson)")
//add formatted number to tempArray
tempArray.append(newPerson)
}
}
//combine all numbers with "," between as a string
let recipString = tempArray.joinWithSeparator(",")
//recipString contains ##########,##########,##########...
extension String {
func digitsOnly() -> String{
let stringArray = self.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = stringArray.joinWithSeparator("")
return newString
}
}
I then add the "recipString" variable to the NSURL in the below code:
let messageBody = "test"
let urlSafeBody = messageBody.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())
if let urlSafeBody = urlSafeBody, url = NSURL(string: "sms:/open?addresses=\(recipString)&body=\(urlSafeBody)") {
print("FINAL URL: \(url)")
WKExtension.sharedExtension().openSystemURL(url)
}
The FINAL URL print shows the correct string, but the messages app does not open properly, and shows quick reply menu instead of composed message window. It matches the functioning hard coded number version exactly, but behaves differently.
Totally lost, hope someone can help!
UPDATE 1
Here are the debug prints for both versions of the URL:
Manually declared (not created from recipString but actually declared in the URL string explicitly):
This version works
FINAL URL: sms:/open?addresses=0000000000,1111111111,2222222222,3333333333,4444444444&body=test
Variable created (using recipString):
This version doesn't
FINAL URL: sms:/open?addresses=0000000000,1111111111,2222222222,3333333333,4444444444&body=test
I have also tried applying url encoding to the "recipString" variable by using the below if let:
if let urlSafeRecip = recipString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) {
if let urlSafeBody = urlSafeBody, url = NSURL(string: "sms:/open?addresses=\(urlSafeRecip)&body=\(urlSafeBody)") {
print("FINAL URL: \(url)")
WKExtension.sharedExtension().openSystemURL(url)
}
}
UPDATE 2
I tested to see if the hardcode version of numbers matches the recipString exactly via this code:
let hardCode = "0000000000,1111111111,2222222222,3333333333,4444444444"
let isEqual = (hardCode == recipString)
if isEqual {
print("hardCode matches recipString")
}
else {
print("hardCode does not match recipString")
}
Debug prints:
hardCode matches recipString
UPDATE 3
I have confirmed that:
When a URL is made with hard coded numbers vs. numbers that I make from variables, checking == between them returns true.
In every test I can do between the two version of the url, it matches.
NOTES AFTER CORRECT ANSWER FOUND:
This type of URL formatting will ONLY work with multiple addresses in the URL. If you do not have multiple addresses you will need to do the following, which is undocumented but none-the-less works. I found this by bashing my face on the keyboard for hours, so if it helps you an upvote is deserved :)
follow the answer marked below, and then use this type of logic check before making the URL in the doItButton() function he mentioned:
func setupAndSendMsg(saveData: NSDictionary) {
if let urlSafeBody = createBody(saveData) {
let theNumbers = createNumbers(saveData).componentsSeparatedByString(",")
print(theNumbers.count-1)
if theNumbers.count-1 > 0 {
if let url = NSURL(string: "sms:/open?addresses=\(createNumbers(saveData))&body=\(urlSafeBody)") {
print(url)
WKExtension.sharedExtension().openSystemURL(url)
}
} else {
if let url = NSURL(string: "sms:/open?address=\(createNumbers(saveData)),&body=\(urlSafeBody)") {
print(url)
WKExtension.sharedExtension().openSystemURL(url)
}
}
}
}
My guess is that it is not the acctual openSystemUrl call that is the problem. I believe there must be something with the code that is building the number string programmatically.
The code bellow is a simplified version of all the code you have posted. I have confirmed that it is working on my Apple Watch. It opens the Messages app with pre-populated numbers & body text.
Take one more look at your code and see if there is something your missing. If you can't find anything, just delete the code and re-write it, probably will be faster then spotting the weird issue.
Once again the code bellow is confirmed working as expected, so you should be able to get it to work. (or just copy & paste my code) :)
class InterfaceController: WKInterfaceController {
#IBAction func doItButton() {
if let urlSafeBody = createBody() {
if let url = NSURL(string: "sms:/open?addresses=\(createNumbers())&body=\(urlSafeBody)") {
print(url)
WKExtension.sharedExtension().openSystemURL(url)
}
}
}
private func createBody() -> String? {
let messageBody = "hello test message"
return messageBody.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())
}
private func createNumbers() -> String {
let numbers = ["(111) 222-3333", "(444) 555-6666"]
var tempArray: [String] = []
numbers.forEach { (number: String) in
tempArray.append(number.digitsOnly())
}
return tempArray.joinWithSeparator(",")
}
}
extension String {
func digitsOnly() -> String{
let stringArray = self.componentsSeparatedByCharactersInSet(
NSCharacterSet.decimalDigitCharacterSet().invertedSet)
let newString = stringArray.joinWithSeparator("")
return newString
}
}
With above said I would recommend against using undocumented Apple features for anything you plan on putting on the App Store for the reasons already mentioned in comments.