I want a regex in swift matches all decimal numbers and integers, the requirement is following:
Reject these non-numbers:
. (single decimal point)
2.2.2 (two or more decimal points in any order)
-. (negative decimal point)
+. (plus decimal point)
(empty string)
Any help appreciated.
Instead of a regex, why not just try converting the String to a Float. You can put the following in a Swift playground to see that it works:
func isNumber(s: String) -> Bool {
return Float(s) != nil
}
// Your criteria
isNumber(".") // false
isNumber("2.2.2") // false
isNumber("-.") // false
isNumber("+.") // false
isNumber("") // false
// Validity check
isNumber("2.2") // true
isNumber("2") // true
isNumber("-2") // true
If validating user input, rather a regex, why not just try converting the String to a number user NSNumberFormatter. This gets you out of writing regex and handles international formats, too (e.g. in Germany, they enter 2.3 as 2,3):
let numberFormatter: NSNumberFormatter = {
let formatter = NSNumberFormatter()
formatter.numberStyle = .DecimalStyle
return formatter
}()
func isNumber(s: String) -> Bool {
return numberFormatter.numberFromString(s) != nil
}
Related
I want to choose a password for the user to have at least 8 characters in the password he chooses, and also the number of letters, and that the duplicate numbers should not be sequential numbers when they want to write the password.
This called NSRegularExpression, in the first you need to declare the regular expression string like this:
let langRexEx = "^[a-z.]+$"
Then create a function to check the string with the regular expression. For example just English chars and dot:
func verifyLanguage(value: String) -> Bool {
var returnValue = true
let langRexEx = "^[a-z.]+$" // just chars and dot
do {
let regex = try NSRegularExpression(pattern: langRexEx)
let nsString = value as NSString
let results = regex.matches(in: value, range: NSRange(location: 0, length: nsString.length))
if results.count == 0
{
returnValue = false
}
} catch let error as NSError {
print("invalid regex: \(error.localizedDescription)")
returnValue = false
}
return returnValue
}
Important note: string of regular is hard to find.
I am beginner in Scala and I was wondering how I can build a function to check if it matches a definite pattern or not?
For example:
def patternFound(s:String): Boolean = (s) match {
case s matches xyxy pattern => true //where x,y are two consecutive characters in the string
case s matches xxyy pattern => false //where x, y are two characters in that string
case (_) => false //default
}
//Here x,y are not definite characters but the string s should match a pattern
//which consist a string of pattern containing characters in alternating positions
patternFound("babab")//true because pattern of xyxy found in it
patternFound("baabba")//false because pattern of xxyy found in it
Can anyone show with an example how I can achieve this?
Looking for a solution which returns true for any occurrence of xyxyxy pattern in a string, but returns false when the pattern is xxyy in that string.
Example: The function should return true if the string is "babab" or
"ababa" (which has pattern xyxy in it), but returns false for "aabba"
or "bbaab" (which has the pattern xxyy in it)
Any help is appreciated! Thank you in advance.
For the two examples you've posted, these two Regex patterns will cover it.
def patternFound(s:String): Boolean = {
val ptrn1 = "(.)(.)\\1\\2".r
val ptrn2 = "(.)\\1(.)\\2".r
s match {
case ptrn1(_,_) => true
case ptrn2(_,_) => true
case _ => false
}
}
proof:
patternFound("rrgg") // res0: Boolean = true
patternFound("hqhq") // res1: Boolean = true
patternFound("cccx") // res2: Boolean = false
But I suspect that your requirements, as stated, are not specific enough to cover exactly what you're looking for.
UPDATE
You're 2nd requirement now makes no sense. Everything that doesn't match the 1st pattern will return false so there's no point in testing for a specific pattern to return false.
def patternFound(s:String): Boolean = {
val ptrn = "(.)(.)\\1\\2".r.unanchored
s match {
case ptrn(_,_) => true
case _ => false
}
}
patternFound("babab") //true because pattern of xyxy found in it
patternFound("baabba") //false because it doesn't match the target pattern
The syntax is not correct.
You need to remove "s matches" from the body of the function, it is already in the method definition line "(s) match".
See also https://docs.scala-lang.org/tour/pattern-matching.html
This might be possible with regular expressions and look arounds, but I just created a helper function:
/**
* Checks for recurring pattern in a String
* #param s The input String to check
* #param patternSize The size of the expected pattern. For example in the String "aabbaabbaabb" the pattern is "aabb" which is a length of 4
*/
def checkPattern(s: String, patternSize: Int): Boolean = {
val grouped = s.grouped(patternSize)
grouped.toSet.size == 1 // everything should be the same
}
Some example usage of that function:
checkPattern("abababab", 2) // true
checkPattern("aabbaabbaabb", 2) // false
checkPattern("aabbaabbaabb", 4) // true
checkPattern("abcabcabc", 3) // true
So for your code you could do use it with some guard statements:
def patternFound(s: String): Boolean = s match {
case "" => false // empty Strings can't have patterns
case s if checkPattern(s, 2) => true
case s if checkPattern(s, 4) => true
case _ => false
}
patternFound("ababababab") // true
patternFound("aabbaabb") // true
patternFound("aabbzz") // false
Edit: I think the other answer is better for what you are looking for, but here is my updated answer for you updated question:
def patternFound(s: String): Boolean = s match {
s.nonEmpty && checkPattern(s, 2)
}
My function should handle every regex and return a true or false. It's working good... still now
func test(_ input: String) -> Bool {
let pattern = ".{7}" //allow exactly 7 numbers
let regex = try! NSRegularExpression(pattern: pattern, options: [NSRegularExpression.Options.caseInsensitive])
let leftover = regex.stringByReplacingMatches(in: input, options: [], range: NSMakeRange(0, input.characters.count), withTemplate: "")
if leftover.isEmpty {
return true
}
return false
}
print(test("123456")) //false
print(test("1234567")) //true
print(test("12345678")) //false
print(test("")) //true - I expect false
So I understand why test("") is false. But how can I fix my regex that it return false?
Sometimes I use the regex .* My function should handle this one, too. So I can't make a check like this
if input.isEmpty {
return false
}
If input is the empty string then leftover will be the empty string
as well, and therefore your function returns true. Another case where
your approach fails is
print(test("12345671234567")) // true (expected: false)
An alternative is to use the range(of:) method of String with the .regularExpression option. Then check if the matched range is the entire string.
In order to match 7 digits (and not 7 arbitrary characters), the
pattern should be \d{7}.
func test(_ input: String) -> Bool {
let pattern = "\\d{7}"
return input.range(of: pattern, options: [.regularExpression, .caseInsensitive])
== input.startIndex..<input.endIndex
}
A solution is to specify that your regex has to match the entire string to be valid, so you can do this by adding ^ and $ at your regex to ensure the start and the end of the string.
let pattern = "^.{7}$" //allow exactly 7 numbers
let regex = try! NSRegularExpression(pattern: pattern, options: [.caseInsensitive])
let numberOfOccurences = regex.numberOfMatches(in: input, options: [], range: NSMakeRange(0, input.utf16.count))
return (numberOfOccurences != 0)
In theory, we should be checking if numberOfOccurences is truly equal to 1 to return true, but checking the start and the end should give you only one or zero match.
I have a number string that is in Arabic language, I want to convert it to English, I use this:
let arabicPhoneNumber = "٠١٠١٢٣٤٥٦٧٨٩"
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "EN")
if let number = formatter.number(from: arabicPhoneNumber)?.stringValue {
print(number) //deletes leading zero
}
the problem is it deletes the leading zero and I want to preserve it as this is a phone number. is there a way to convert phone number string from Arabic to English without losing leading zeros ??
Instead of converting the string to a number, you can do a "transliteration" to the Latin script, using CFStringTransform() from the Foundation library:
let arabicPhoneNumber = "٠١٠١٢٣٤٥٦٧٨٩"
// We need a CFMutableString and a CFRange:
let cfstr = NSMutableString(string: arabicPhoneNumber) as CFMutableString
var range = CFRange(location: 0, length: CFStringGetLength(cfstr))
// Do the transliteration (this mutates `cfstr`):
CFStringTransform(cfstr, &range, kCFStringTransformToLatin, false)
// Convert result back to a Swift string:
let phoneNumber = cfstr as String
print(phoneNumber) // 010123456789
This preserves all digits as well as possible separators.
Remark: The above example (from the question) contains "Arabic Indic" digits, for example ١ = U+0661 = "ARABIC-INDIC DIGIT ONE".
These are correctly transliterated on macOS 10.12 and iOS 10.
On earlier OS versions,
CFStringTransform(cfstr, &range, kCFStringTransformLatinArabic, true)
CFStringTransform(cfstr, &range, kCFStringTransformStripCombiningMarks, false)
worked correctly in my tests to convert arabic digits to latin.
swift 4.0
func convertToEnDigits(_ digits: String) -> String {
// We need a CFMutableString and a CFRange:
let cfstr = NSMutableString(string: digits) as CFMutableString
var range = CFRange(location: 0, length: CFStringGetLength(cfstr))
// Do the transliteration (this mutates `cfstr`):
CFStringTransform(cfstr, &range, kCFStringTransformToLatin, false)
// Convert result back to a Swift string:
return (cfstr as String)
}
This question already has answers here:
Match exact string
(3 answers)
Closed 6 years ago.
I am working on a username regex where the only characters that are accepted are a-z, A-Z, 0-9, and _. The current max length of the username is 18 characters with a minimum of one. My current regex is below.
let regexCorrectPattern = "[a-zA-Z0-9_]{1,18}$"
I am having the following issue. Special characters added anywhere but the end of the string allow the regex to pass. For example
jon! FAIL
!jon PASS
j!on PASS
The method I am using to test the regex is below along with the calling method. Any input would be greatly appreciated.
Regex Testing Method
func regexTestString(string: String, withPattern regexPattern: String) -> Bool
{
// This method is used for all of the methods below.
do
{
// Create regex and regex range.
let regex = try NSRegularExpression(pattern: regexPattern, options: .CaseInsensitive)
let range = NSMakeRange(0, string.characters.count)
// Test for the number of regex matches.
let numberOfMatches = regex.numberOfMatchesInString(string, options: [], range: range)
// Testing Code.
print(numberOfMatches)
// Return true if the number of matches is greater than 1 and return false if the number of mathces is 0.
return (numberOfMatches == 0) ? false : true
}
catch
{
// Testing Code
print("There is an error in the SignUpViewController regexTestString() method \(error)")
// If there is an error return false.
return false
}
}
Calling Method
func usernameTextFieldDidEndEditing(sender: AnyObject)
{
let usernameText = self.usernameField.text!.lowercaseString
let regexCorrectPattern = "[a-zA-Z0-9_]{1,18}$"
let regexWhitespacePattern = "\\s"
let regexSpecialCharacterPattern = ".*[^A-Za-z0-9].*"
if regexTestString(usernameText, withPattern: regexCorrectPattern)
{
// The regex has passed hide the regexNotificationView
}
else if regexTestString(usernameText, withPattern: regexWhitespacePattern)
{
// The username contains whitespace characters. Alert the user.
}
else if regexTestString(usernameText, withPattern: regexSpecialCharacterPattern)
{
// The username contains special characters. Alert the user.
}
else if usernameText == ""
{
// The usernameField is empty. Make sure the sign up button is disabled.
}
else
{
// For some reason the Regex is false. Disable the sign up button.
}
}
You want the entire string to contain only the characters you specified, so all you need is to add ^ at the start of the pattern:
^[a-zA-Z0-9_]{1,18}$