Swift中数字间可选下划线的正则表达式验证问题
Hey there! Let's break down why your current regex isn't working, then fix it up to perfectly fit your validation rules for Swift.
Why Your Regex Fails
Your current pattern ([0-9]+_*[0-9]+)* has three key issues that make it fail your validation rules:
- No full-string anchoring: Without
^(start of string) and$(end of string), the regex will match any valid substring within an invalid string. For example,abc123_defwould be incorrectly marked as valid because it contains123_def. - Allows consecutive underscores: The
_*matches 0 or more underscores, so strings like123__45slip through even though they violate your "underscores only between numbers" rule. - Permits empty strings: The outer
(...)*allows the entire group to repeat 0 times, which means an empty string would be considered valid—something you definitely don't want.
The Correct Regex for Your Rules
You need a pattern that enforces:
- Only digits and underscores are allowed
- Underscores must be between digits (no leading/trailing underscores, no consecutive underscores)
- At least one digit is present
Here's the regex that checks all these boxes:
^[0-9]+(?:_[0-9]+)*$
Let's break this down:
^: Anchors the match to the start of the string[0-9]+: Matches one or more digits (ensures we start with a digit and have at least one number)(?:_[0-9]+)*: A non-capturing group that matches an underscore followed by one or more digits. The*means this group can repeat 0 or more times (allowing no underscores, or multiple valid underscore-separated digit groups)$: Anchors the match to the end of the string, ensuring the entire string is validated
Implementing in Swift
Here's a clean Swift function that uses this regex to validate your strings. We'll use NSRegularExpression for reliable matching:
import Foundation func isValidNumberString(_ input: String) -> Bool { let validationPattern = "^[0-9]+(?:_[0-9]+)*$" guard let regex = try? NSRegularExpression(pattern: validationPattern) else { // If regex fails to compile (shouldn't happen here), return false return false } let fullStringRange = NSRange(input.startIndex..., in: input) // Check if the entire string matches the pattern return regex.firstMatch(in: input, range: fullStringRange) != nil } // Test your examples to verify let validStrings = ["123", "1_23", "123_4567_89_312_575"] let invalidStrings = ["123_", "_123", "123__12", "_", "abc"] print("Valid String Results:") validStrings.forEach { print("\($0): \(isValidNumberString($0))") } print("\nInvalid String Results:") invalidStrings.forEach { print("\($0): \(isValidNumberString($0))") }
If you prefer a more concise version, you can use String's built-in range(of:options:) method:
func isValidNumberString(_ input: String) -> Bool { return input.range(of: "^[0-9]+(?:_[0-9]+)*$", options: [.regularExpression, .anchored]) != nil }
Both implementations will correctly validate your test cases, rejecting all invalid examples and accepting the valid ones.
内容的提问来源于stack exchange,提问作者Pradeep Rajkumar

