Jak możemy sprawdzić, czy ciąg składa się tylko z liczb. Pobieram podciąg z ciągu i chcę sprawdzić, czy jest to podciąg numeryczny, czy nie.
NSString *newString = [myString substringWithRange:NSMakeRange(2,3)];
Odpowiedzi:
Oto jeden sposób, który nie polega na ograniczonej precyzji próby przeanalizowania ciągu jako liczby:
NSCharacterSet* notDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
if ([newString rangeOfCharacterFromSet:notDigits].location == NSNotFound)
{
// newString consists only of the digits 0 through 9
}
Zobacz +[NSCharacterSet decimalDigitCharacterSet]
i -[NSString rangeOfCharacterFromSet:]
.
[[NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet]]
invertedSet
zwraca klasę, która zawija zestaw, w którym została utworzona, i zwraca przeciwną wartość dla wszystkich zapytań. Ale nie wiem na pewno.
Sugerowałbym użycie numberFromString:
metody z klasy NSNumberFormatter , tak jakby numer był niepoprawny, zwróci nil; w przeciwnym razie zwróci Ci NSNumber.
NSNumberFormatter *nf = [[[NSNumberFormatter alloc] init] autorelease];
BOOL isDecimal = [nf numberFromString:newString] != nil;
NO
Twój ciąg. Warto również wiedzieć: powracają również YES
po liczbach wypełnionych spacjami. Przy okazji, właśnie dodałem fragment kodu do Twojej odpowiedzi, mam nadzieję, że nie masz nic przeciwko.
Sprawdź poprawność za pomocą wyrażenia regularnego, według wzorca "^[0-9]+$"
, przy użyciu następującej metody -validateString:withPattern:
.
[self validateString:"12345" withPattern:"^[0-9]+$"];
"^[0-9]+(.{1}[0-9]+)?$"
"."
.
"^[0-9]{4}$"
."."
, a długość wynosi od 2 do 5.
"^[0-9]{2,5}$"
."^-?\d+$"
Wyrażenie regularne można sprawdzić w witrynie internetowej online .
Funkcja pomocnicza jest następująca.
// Validate the input string with the given pattern and
// return the result as a boolean
- (BOOL)validateString:(NSString *)string withPattern:(NSString *)pattern
{
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern options:NSRegularExpressionCaseInsensitive error:&error];
NSAssert(regex, @"Unable to create regular expression");
NSRange textRange = NSMakeRange(0, string.length);
NSRange matchRange = [regex rangeOfFirstMatchInString:string options:NSMatchingReportProgress range:textRange];
BOOL didValidate = NO;
// Did we find a matching range
if (matchRange.location != NSNotFound)
didValidate = YES;
return didValidate;
}
Przetestuj na placu zabaw.
import UIKit
import Foundation
func validate(_ str: String, pattern: String) -> Bool {
if let range = str.range(of: pattern, options: .regularExpression) {
let result = str.substring(with: range)
print(result)
return true
}
return false
}
let a = validate("123", pattern: "^-?[0-9]+")
print(a)
func numberOnly(string: String) -> Int { let expression = "" let regex = NSRegularExpression.init(pattern: expression, options: .caseInsensitive) let numberOfMatches = regex.numberOfMatches(in: string, options: .reportProgress, range: NSRange.init(location: 0, length: string.characters.count)) if numberOfMatches == 0 { return Int(string)! } return 0 }
I otrzymałem błądPlayground execution aborted: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
return matchRange.location != NSNotFound;
^-?\d+$
, zweryfikowałem to na stronie: regex101.com
Możesz utworzyć NSScanner i po prostu zeskanować ciąg:
NSDecimal decimalValue;
NSScanner *sc = [NSScanner scannerWithString:newString];
[sc scanDecimal:&decimalValue];
BOOL isDecimal = [sc isAtEnd];
Sprawdź dokumentację NSScanner, aby uzyskać więcej metod do wyboru.
isAtEnd
.
Myślę, że najłatwiejszym sposobem sprawdzenia, czy każdy znak w danym ciągu jest numeryczny, jest prawdopodobnie:
NSString *trimmedString = [newString stringByTrimmingCharactersInSet:[NSCharacterSet decimalDigitCharacterSet]];
if([trimmedString length])
{
NSLog(@"some characters outside of the decimal character set found");
}
else
{
NSLog(@"all characters were in the decimal character set");
}
Użyj jednej z innych metod fabryki NSCharacterSet, jeśli chcesz mieć pełną kontrolę nad dopuszczalnymi znakami.
To pierwotne pytanie dotyczyło Objective-C, ale zostało również opublikowane wiele lat przed ogłoszeniem Swift. Jeśli więc przyjeżdżasz tutaj z Google i szukasz rozwiązania wykorzystującego Swift, proszę bardzo:
let testString = "12345"
let badCharacters = NSCharacterSet.decimalDigitCharacterSet().invertedSet
if testString.rangeOfCharacterFromSet(badCharacters) == nil {
print("Test string was a number")
} else {
print("Test string contained non-digit characters.")
}
Rozwiązanie Swift 3, jeśli chcesz sprawdzić, czy ciąg ma tylko cyfry:
CharacterSet.decimalDigits.isSuperset(of: CharacterSet(charactersIn: myString))
.inverted
i innych działań.
aby było jasne, to działa dla liczb całkowitych w łańcuchach.
Oto mała kategoria pomocnicza oparta na odpowiedzi Johna powyżej:
w pliku h
@interface NSString (NumberChecking)
+(bool)isNumber:(NSString *)string;
@end
w pliku m
#import "NSString+NumberChecking.h"
@implementation NSString (NumberChecking)
+(bool)isNumber {
if([self rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location == NSNotFound) {
return YES;
}else {
return NO;
}
}
@end
stosowanie:
#import "NSString+NumberChecking.h"
if([someString isNumber]) {
NSLog(@"is a number");
}else {
NSLog(@"not a number");
}
Rozwiązanie Swift 3 mogłoby wyglądać następująco:
extension String {
var doubleValue:Double? {
return NumberFormatter().number(from:self)?.doubleValue
}
var integerValue:Int? {
return NumberFormatter().number(from:self)?.intValue
}
var isNumber:Bool {
get {
let badCharacters = NSCharacterSet.decimalDigits.inverted
return (self.rangeOfCharacter(from: badCharacters) == nil)
}
}
}
Rozszerzenie odpowiedzi @John Calsbeek i wyjaśnienie komentarzy @Jeff i @gyratory circus .
+ (BOOL)doesContainDigitsOnly:(NSString *)string
{
NSCharacterSet *nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
BOOL containsDigitsOnly = [string rangeOfCharacterFromSet:nonDigits].location == NSNotFound;
return containsDigitsOnly;
}
+ (BOOL)doesContainNonDigitsOnly:(NSString *)string
{
NSCharacterSet *digits = [NSCharacterSet decimalDigitCharacterSet];
BOOL containsNonDigitsOnly = [string rangeOfCharacterFromSet:digits].location == NSNotFound;
return containsNonDigitsOnly;
}
Poniższe można dodać jako metody kategorii dla NSString
- (BOOL)doesContainDigitsOnly
{
NSCharacterSet *nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet];
BOOL containsDigitsOnly = [self rangeOfCharacterFromSet:nonDigits].location == NSNotFound;
return containsDigitsOnly;
}
- (BOOL)doesContainNonDigitsOnly
{
NSCharacterSet *digits = [NSCharacterSet decimalDigitCharacterSet];
BOOL containsNonDigitsOnly = [self rangeOfCharacterFromSet:digits].location == NSNotFound;
return containsNonDigitsOnly;
}
Odpowiedź Johna Calsbeeka jest prawie poprawna, ale pomija niektóre przypadki Unicode.
Zgodnie z dokumentacjądecimalDigitCharacterSet
, ten zestaw zawiera wszystkie znaki sklasyfikowane przez Unicode jako Nd
. W ten sposób ich odpowiedź przyjmie m.in .:
१
(U + 0967 DEVANAGARI DIGIT ONE)᠑
(U + 1811 MONGOLIAN DIGIT ONE)𝟙
(U + 1D7D9 MATEMATYCZNA PODWÓJNA CYFROWA CYFRA)Chociaż w pewnym sensie jest to poprawne - każdy znak Nd
odwzorowuje cyfrę dziesiętną - prawie na pewno nie jest to to, czego oczekiwał pytający. W chwili pisania tego tekstu istnieje 610 punktów kodowych sklasyfikowanych jakoNd
, z których tylko dziesięć to oczekiwane znaki 0
(od U + 0030) do9
(U + 0039).
Aby rozwiązać problem, po prostu określ dokładnie te znaki, które są dopuszczalne:
NSCharacterSet* notDigits =
[[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet];
if ([newString rangeOfCharacterFromSet:notDigits].location == NSNotFound)
{
// newString consists only of the digits 0 through 9
}
Jeszcze inna opcja:
- (BOOL)isValidNumber:(NSString*)text regex:(NSString*)regex {
@try {
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
return [predicate evaluateWithObject:text];
}
@catch (NSException *exception) {
assert(false);
return NO;
}
}
Przykład użycia:
BOOL isValid = [self isValidNumber:@"1234" regex:@"^[0-9]+$"];
Sprawdź, czy ciąg jest liczbą. Może być pomocny
int i = [@"12.3" rangeOfCharacterFromSet: [ [NSCharacterSet characterSetWithCharactersInString:@"0123456789."] invertedSet] ].location;
if (i == NSNotFound) {
//is a number
}
Szybkie rozszerzenie:
extension NSString {
func isNumString() -> Bool {
let numbers = NSCharacterSet(charactersInString: "0123456789.").invertedSet
let range = self.rangeOfCharacterFromSet(numbers).location
if range == NSNotFound {
return true
}
return false
} }
Dla Swift 3
var onlyDigits: CharacterSet = CharacterSet.decimalDigits.inverted
if testString.rangeOfCharacter(from: onlyDigits) == nil {
// String only consist digits 0-9
}
Jeśli masz cyfry z języków mieszanych , które używają (lub nie) formatów cyfr 0-9, będziesz musiał uruchomić wyrażenie regularne, które będzie szukało dowolnej liczby, a następnie przekonwertuj wszystkie cyfry na 0- 9 format (jeśli potrzebujesz rzeczywistej wartości):
// Will look for any language digits
let regex = try NSRegularExpression(pattern: "[^[:digit:]]", options: .caseInsensitive)
let digitsString = regex.stringByReplacingMatches(in: string,
options: NSRegularExpression.MatchingOptions(rawValue: 0),
range: NSMakeRange(0, string.count), withTemplate: "")
// Converting the digits to be 0-9 format
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "EN")
let finalValue = numberFormatter.number(from: digitsString)
if let finalValue = finalValue {
let actualValue = finalValue.doubleValue
}
Najłatwiejszym i najbardziej niezawodnym sposobem jest próba rzucenia, ponieważ Double
jeśli wynik jest nil
- nie można go uformować w legalną liczbę.
let strings = ["test", "123", "123.2", "-123", "123-3", "123..22", ".02"]
let validNumbers = strings.compactMap(Double.init)
print(validNumbers)
// prints [123.0, 123.2, -123.0, 0.02]
Więcej informacji w dokumentacji: https://developer.apple.com/documentation/swift/double/2926277-init
.
znaku