I have this textfield
TextField("Your e-mail...",
text: $email)
.keyboardType(.emailAddress)
.textContentType(.emailAddress)
.disableAutocorrection(true)
.autocapitalization(.none)
I type anything and I see no error. Double #, multiple dots and so one. No error so far.
How is this supposed to work?
Your code only adds suggestions/custom keyboard for email addresses. It does not validate whether or not a user entered a valid email address.
To return whether or not the field contains a valid email address, you will need to run the entered string through a function that utilizes regex:
func isValidEmailAddr(strToValidate: String) -> Bool {
let emailValidationRegex = "^[\\p{L}0-9!#$%&'*+\\/=?^_`{|}~-][\\p{L}0-9.!#$%&'*+\\/=?^_`{|}~-]{0,63}#[\\p{L}0-9-]+(?:\\.[\\p{L}0-9-]{2,7})*$"
let emailValidationPredicate = NSPredicate(format: "SELF MATCHES %#", emailValidationRegex)
return emailValidationPredicate.evaluate(with: strToValidate)
}
If an error is returned, you can then do something with that response i.e. show an error to the user.
Related
The below is a challenge assignment so may not reflect 'real-world' code. I am trying to setup my method in a way that uses the properties of one hash to return a new hash. In this case, my method is taking an email as a string, uses regex to extrapolate the tld of the email and then outputs a hash-based message based of the tld. In this example, it generates an email in the language of the tld it registers.
The code works as it should but is failing one test:
"should return a Hash with the message informations in english for any other ccTlD mail"
I cannot work out how to just set up a default value of 'en' when the tld is not in the original translation hash i.e. bob#gmail.pl should just return the English-based translation.
BONUS: I also note that my Rubocop doesn't like my styling because my compose_translated_email method has too many lines. I couldn't work out how to put the translation in another method without making that method too long too.
Any help would be greatly appreciated - rather than just the answer, I would love if you could explain what the code is doing too. Thank you.
LOCALES = {
en: {
subject: "Our website is online",
body: "Come and visit us!",
closing: "See you soon",
signature: "The Team"
},
fr: {
subject: "Notre site est en ligne",
body: "Venez nous rendre visite !",
closing: "A bientot",
signature: "L'équipe"
},
de: {
subject: "Unsere Website ist jetzt online",
body: "Komm und besuche uns!",
closing: "Bis bald",
signature: "Das Team"
}
}
def compose_translated_email(email)
username = email.match(/^(\w*)/)[1]
domain = email.match(/[^#]+(?=\.)/)[0]
tld = email.match(/.*\.(\w+)$/)[1]
tldsym = tld.to_sym
new_hash = {
username: username,
domain: domain,
tld: tld,
subject: LOCALES[tldsym][:subject],
body: LOCALES[tldsym][:body],
closing: LOCALES[tldsym][:closing],
signature: LOCALES[tldsym][:signature]
}
return new_hash
end
Wouldn't it be enough to default the value of tld to en before creating the hash? As in:
(...)
# default to english language
tldsym = tld.to_sym
# i.e. if the key does not exist in LOCALES, use "en" as key
tldsym = LOCALES.key?(tldsym) ? tldsym : "en".to_sym
(...)
Considering your bonus question, you might fill the translated values via loop to save a few lines:
(...)
new_hash = {
username: username,
domain: domain,
tld: tld,
}
%i(subject body closing signature).each { |k| new_hash[k] = LOCALES[tldsym][k] }
(...)
Explanation: We're iterating over an array of key names (subject, body, closing, signature) that will be filled in from the LOCALES hash. That %i notation (requires Ruby 2.0.0 or newer) gives us an array with symbols to these keys right away, so no to_sym is needed inside the each block - we can just use the current symbols (named k in this case) in both the source and the target hash.
Save additional lines by filling the other hash slots iteratively, too:
(...)
new_hash = {}
%W(username domain tld).each { |k| new_hash[k.to_sym] = eval(k) }
%i(subject body closing signature).each { |k| new_hash[k] = LOCALES[tldsym][k] }
(...)
Explanation: Here we're using %W to get an array of strings, so we need to_sym for the key in the target. The target value is then resolved using evaluation, which is probably not considered the cleanest style, I guess.
Please forgive any stupid mistakes, I'm a Ruby beginner myself :)
I would do something like this:
LOCALES = Hash.new({
subject: "Our website is online",
body: "Come and visit us!",
closing: "See you soon",
signature: "The Team"
}).merge({
'fr' => {
subject: "Notre site est en ligne",
body: "Venez nous rendre visite !",
closing: "A bientot",
signature: "L'équipe"
},
'de' => {
subject: "Unsere Website ist jetzt online",
body: "Komm und besuche uns!",
closing: "Bis bald",
signature: "Das Team"
}
}).freeze
def compose_translated_email(email)
email.scan(/([^#]+)#(.*\.([^.]+))/) => [[username, domain, tld]]
{
username:,
domain:,
tld:,
**LOCALES[tld]
}
end
It's not the most beautiful code in the world, but it'll do.
I am trying to create a Form with apps script and for some reason it will not allow the simplest phone number validation in a TextItem input field. I only need the user to enter their 10 digit number with no spaces, dashes, dots, with area code included. I know this isn't the technical "best" way to validate phone numbers but for our purposes it works. This is section of code I have to generate the field. (edited to make a more reproducible example)
function CreateForm() {
var form = FormApp.create('Test');
var tenantNum = form.addTextItem()
.setTitle("Tenant Phone #");
var phoneValid = FormApp.createTextValidation()
.setHelpText("Please enter valid phone number, 10-digits, no symbols or spaces.")
.requireTextMatchesPattern(/\d{10}/g)
.build();
tenantNum.setValidation(phoneValid);
console.log(form.getPublishedUrl())
}
I have also tried other things like:
(No capture group or global tag, both individually)
.requireTextMatchesPattern(/\d{10}/)
Entering the regex as a string literal.
.requireTextMatchesPattern("\d{10}")
Even dumdum stuff like.
.requireTextMatchesPattern(/[0-9]{10}/)
or
.requireTextMatchesPattern(/\d\d\d\d\d\d\d\d\d\d/)
Just to see if it works. I have also tried .requireTextContainsPattern() as well.
Whenever you enter in the form however i get this response:
Please enter valid phone number, 10-digits, no symbols or spaces.
My only thought is that there might be some confusion with whether or not the user is entering a string vs. number and this method only works on strings. But this validation
and regex work fine when you enter it into the form creation manually so I'm completely lost. Any help is appreciated!
Just a guess... Try this:
.requireTextMatchesPattern("\\d{10}")
Update
It works fine for me:
function CreateForm() {
var form = FormApp.create('Test');
var tenantNum = form.addTextItem()
.setTitle("Tenant Phone #");
var phoneValid = FormApp.createTextValidation()
.setHelpText("Please enter valid phone number, 10-digits, no symbols or spaces.")
.requireTextMatchesPattern("\\d{10}")
.build();
tenantNum.setValidation(phoneValid);
console.log(form.getPublishedUrl())
}
And the "not existed" method setHelpText() works fine as well, as you can tell from the screenshots.
The user is asked to fill in a field with a tag containing no hashtags and no spaces. But some will no doubt do it anyway. How do I strip the hashtags and spaces before sending it off to the database? Here's the code I used to try and simply remove the hashtag. But although it prints the correct removal in the console in realtime as I type into the field, I get the following error when I try to post it off to the server:
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: Invalid argument(s) (input): Must not be null
So here's the code;
child: TextField(
keyboardType: TextInputType.text,
autocorrect: false,
onChanged: (tag1text){
nohash1 = tag1text.replaceAll('#', '');
print("This is nohash1 " + nohash1);
setState(() {
this.tag1 = nohash1;
});
},
),
You can try .replaceAll(RegExp('[# ]'),'') . Your original code only removed matching #. Using RegExp('[# ]') we can specify the regex pattern to use for removal.
void main() {
String inputText = '#big dog sled';
print(inputText.replaceAll(RegExp('[# ]'),''));
}
Output :
bigdogsled
My MPMediaplayer is working pretty well for Music, but when I start working with Podcasts things are different.
I'm trying to get two things:
1) The name the Podcast Title ("This American Life")
2) The Episode Title ("My Holiday")
This line of code works fine to get the Podcast Title:
let podTitle:String = (myMP.nowPlayingItem?.podcastTitle)!
However this line should get the Episode Title:
let episode:String = myMP.nowPlayingItem?.value(forProperty: "MPMediaItemPropertyTitle") as! String
but causes a crash with this error:
fatal error: unexpectedly found nil while unwrapping an Optional value
How can I get the Episode Title for a given Podcast?
MPMediaItemPropertyTitle is not the string property key; it is the name of a constant whose value is the property key. So, where you have
let episode:String =
myMP.nowPlayingItem?.value(forProperty: "MPMediaItemPropertyTitle") as! String
...remove the quotation marks:
let episode:String =
myMP.nowPlayingItem?.value(forProperty: MPMediaItemPropertyTitle) as! String
I think what you are doing is still very foolish (you are asking to crash), but at least this way you stand a chance of success. What I do is actually more like this:
let temp = myMP.nowPlayingItem?.value(forProperty: MPMediaItemPropertyTitle)
let episode = temp as? String ?? ""
That way you always end up with a string, which may be empty if there's a problem, and you won't crash.
I've tried implementing a rather simple email validation function that seems return a false match even though the input is a valid email. I have searched for any issues with the existing regex but it seems to be correct.
Even though the match returns a false value the program is stepping to the next validation level (which it shouldn't).
Here is the email validation function.
Function EmailAddressChecker(ByVal emailAddress As String) As Boolean
Dim regExPattern As String = "^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$"
Dim emailAddressMatch As Match = Regex.Match(emailAddress, regExPattern)
If emailAddressMatch.Success Then
Return True
Else
Return False
End If
End Function
And for the form validation that calls upon the email validation function.
If (String.IsNullOrEmpty(EmailTextBox.Text) OrElse EmailAddressChecker(EmailTextBox.ToString)) Then
MessageBox.Show("Please enter a valid email addresss")
Return False
End If
The call for all of this happens on an click event which triggers a cascading serious of If statements checking to see if all the fields are set.
Skipping a large chunk of code the click event asks if "AreFieldsSet <> True". Inside of the "AreFieldsSet" function contains all the validation for multiple inputs; one of which is the email validation if statement.
Are the emails in UpperCase? If they aren't, they won't match.
If you want to modify the Regex so that it is Case insensitive, use this:
"^[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$"
To validate the email address you need to use the IsMatch function of the Regex object, it evaluate if the entry email address is valid.
Function EmailAddressChecker(ByVal emailAddress As String) As Boolean
Dim r As System.Text.RegularExpressions.Regex = Nothing
Dim regExPattern As String = "^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$"
If r.IsMatch(emailAddress ,regExPattern ) Then
Return True
Else
Return False
End If
End Function
You can try this code for your form validation If (String.IsNullOrEmpty(EmailTextBox.Text) OrElse EmailAddressChecker(EmailTextBox.ToString)<>true) Then
MessageBox.Show("Please enter a valid email addresss")
Return False
End If
Public Shared Function ValidEmailAddress(ByVal emailAddress As String, ByRef errorMessage As String) As Boolean
If emailAddress.IndexOf("#") > -1 Then
If (emailAddress.IndexOf(".", emailAddress.IndexOf("#")) > emailAddress.IndexOf("#")) AndAlso emailAddress.Split(".").Length > 0 AndAlso emailAddress.Split(".")(1) <> "" Then
errorMessage = ""
Return True
End If
End If
Return False
End Function