I created the following method to strip characters from a phone number but calling it is triggering error "use of undeclared identifier". Can anyone see what I am doing wrong? Do I have to put a reference to this in .h file? Or why won't it work.
-(id)stripTel:(NSString*) phoneno {
NSString *condensedPhoneno = [[phoneno componentsSeparatedByCharactersInSet:
[[NSCharacterSet characterSetWithCharactersInString:#"+0123456789"]
invertedSet]]
componentsJoinedByString:#""];
return condensedPhoneno;
}
-otherFunction {
NSString *oldnum = #"2334332(21)33-)";
NSString *newnum = stripTel:oldnum;
NSLog(#"newnum%#",newnum);
}
You need to call:
NSString *newnum = [self stripTel:oldnum];
and I can see one more mistake, should be:
- (void) otherFunction {
Use below code to trim the extra characters from your textfield
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if(textField == _txtFld_MobileNo )
{
if (range.length == 1)
{
// Delete button was hit.. so tell the method to delete the last char.
_txtFld_MobileNo.text = [self formatPhoneNumber:totalString deleteLastChar:YES];
}
else
{
_txtFld_MobileNo.text = [self formatPhoneNumber:totalString deleteLastChar:NO ];
}
return false;
}
-(NSString*) formatPhoneNumber:(NSString*) simpleNumber deleteLastChar:(BOOL)deleteLastChar
{
if(simpleNumber.length==0) return #"";
// use regex to remove non-digits(including spaces) so we are left with just the numbers
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[\\s-\\(\\)]" options:NSRegularExpressionCaseInsensitive error:&error];
simpleNumber = [regex stringByReplacingMatchesInString:simpleNumber options:0 range:NSMakeRange(0, [simpleNumber length]) withTemplate:#""];
// check if the number is to long
if(simpleNumber.length>10)
{
// remove last extra chars.
simpleNumber = [simpleNumber substringToIndex:10];
}
if(deleteLastChar)
{
// should we delete the last digit?
simpleNumber = [simpleNumber substringToIndex:[simpleNumber length] - 1];
}
// 123 456 7890
// format the number.. if it's less then 7 digits.. then use this regex.
if(simpleNumber.length<7)
simpleNumber = [simpleNumber stringByReplacingOccurrencesOfString:#"(\\d{3})(\\d+)"
withString:#"($1) $2"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [simpleNumber length])];
else // else do this one..
simpleNumber = [simpleNumber stringByReplacingOccurrencesOfString:#"(\\d{3})(\\d{3})(\\d+)"
withString:#"($1) $2-$3"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [simpleNumber length])];
return simpleNumber;
}
Related
I want alphanumeric value in textfield.If user enter only character or number then sending massage.Even no special characters acceptable.
NSString *str = askIdTxt.text;
NSCharacterSet *alphanumericSet = [NSCharacterSet alphanumericCharacterSet];
NSCharacterSet *numberSet = [NSCharacterSet decimalDigitCharacterSet];
BOOL isAlphaNumericOnly = [[str stringByTrimmingCharactersInSet:alphanumericSet] isEqualToString:#""] && ! [[str stringByTrimmingCharactersInSet:numberSet] isEqualToString:#""];
if (isAlphaNumericOnly) {
NSLog(#"isAplhaNumericOnly: %#",(isAlphaNumericOnly? #"Yes":#"No"));
}
This is always returning true. I am not getting what is wrong in this.
How about using regular expression:
-(BOOL)isAlphaNumericOnly:(NSString *)input
{
NSString *alphaNum = #"[a-zA-Z0-9]+";
NSPredicate *regexTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", alphaNum];
return [regexTest evaluateWithObject:input];
}
and then use it
if([self isAlphaNumeric:str])
{
NSLog(#"IT IS ALPHA NUMERIC STRING");
}
edit
The same technique can be used to validate passwords, you need only better regex:
-(BOOL)isPasswordStrong:(NSString *)password {
/*
8-20 chars
at least one letter
at least one number OR special character
no more than 3 repeated characters
*/
NSString *strongPass= #"^(?!.*(.)\\1{3})((?=.*[\\d])(?=.*[A-Za-z])|(?=.*[^\\w\\d\\s])(?=.*[A-Za-z])).{8,20}$";;
NSPredicate *regexTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", strongPass];
return [regexTest evaluateWithObject:password];
}
using the regular expression you can create different rules but this can give you a headstart,
Call this Method and modify it accordingly .....
-(BOOL) isPasswordValid:(NSString *)pwd
{
if ( [pwd length]<4 || [pwd length]>20 ) return NO; // too long or too short
NSRange rang;
rang = [pwd rangeOfCharacterFromSet:[NSCharacterSet letterCharacterSet]];
if ( !rang.length ) return NO; // no letter
rang = [pwd rangeOfCharacterFromSet:[NSCharacterSet decimalDigitCharacterSet]];
if ( !rang.length ) return NO; // no number;
return YES;
}
I guess the problem is in the alphanumericCharacterSet, here is a part from doc:
Informally, this set is the set of all characters used as basic units
of alphabets, syllabaries, ideographs, and digits.
So, I am expecting it would allow the unwanted characters to you.
You may also try using Regex:
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"^[a-z\\d]+$" options:NSRegularExpressionCaseInsensitive error:&error];
NSUInteger matches = [regex numberOfMatchesInString:str options:NSMatchingReportCompletion range:NSMakeRange(0, [str length])];
BOOL hasMatches = (matches > 0) && !error;
Try this
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
NSCharacterSet *charactersToBlock = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
return ([string rangeOfCharacterFromSet:charactersToBlock].location == NSNotFound);
}
Try this :
NSCharacterSet *blockedCharacters = [[[NSCharacterSet alphanumericCharacterSet] invertedSet] retain];
- (BOOL)textField:(UITextField *)field shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)characters
{
return ([characters rangeOfCharacterFromSet:blockedCharacters].location == NSNotFound);
}
Hi im trying to remove som HTML string from a web response. I want to remove <pre><a style="" name="output-line-1">1</a>, were the who instances of number "1"varies, but is always a digit. but how do i write the regex method for removing this? Below is what i have got so far:
-(NSString *)stringByStrippingHTML:(NSString*)str
{
NSRange r;
while ((r = [str rangeOfString:#"/^<pre><a style=\"\"name=\"output-line-([0-9])\">([0-9])</a>" options:NSRegularExpressionSearch]).location != NSNotFound){
str = [str stringByReplacingCharactersInRange:r withString:#""];
}
}
Basically I want to remove a substring with random number in it... In some instances of the substring the 1 is replaced, so that any similar string gets acknowledged, for example it could be output-line-999. How do i combine the range of string so i can both describe the string and specify to find any similar string with any number?
I want to remove both the HTML and the numbers.
This regular expression should work:
[str rangeOfString:#"<pre><a style=\"\" name=\"output-line-[0-9]+\">[0-9]+</a>" options:NSRegularExpressionSearch];
I thnk the problem is that there ins't a space before name in your reg expression
Using your original while loop, you can:
-(NSString *)stringByStrippingHTML:(NSString*)str
{
NSRange r;
while ((r = [str rangeOfString:#"<pre><a style=\"\" name=\"output-line-[0-9]+\">[0-9]+</a>" options:NSRegularExpressionSearch]).location != NSNotFound)
{
str = [str stringByReplacingCharactersInRange:r withString:#""];
}
}
Or you can use NSRegularExpression:
NSMutableString *input = ...
NSError *error;
NSRegularExpression *regex;
regex = [NSRegularExpression regularExpressionWithPattern:#"<pre><a style=\"\" name=\"output-line-[0-9]+\">[0-9]+</a>"
options:0
error:&error];
if (error)
{
NSLog(#"error=%#",error);
return;
}
[regex replaceMatchesInString:input
options:0
range:NSMakeRange(0, [input length])
withTemplate:#""];
I would like to use regular expression to find every instances of a regular expression pattern I.e. &*; in my string and remove that from so the return value is the original string without any of the matches. Also would like to use the same function to match multiple spaces between words and have a single space instead. Could not find such a function.
Sample input string
NSString *str = #"123 &1245; Ross Test 12";
Return value should be
123 Ross Test 12
If anything matching this pattern "&* or multiple white spaces and replaces it with #"";
NSString *string = #"123 &1245; Ross Test 12";
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"&[^;]*;" options:NSRegularExpressionCaseInsensitive error:&error];
NSString *modifiedString = [regex stringByReplacingMatchesInString:string options:0 range:NSMakeRange(0, [string length]) withTemplate:#""];
NSLog(#"%#", modifiedString);
String replacing code using regex in String extension
Objective-C
#implementation NSString(RegularExpression)
- (NSString *)replacingWithPattern:(NSString *)pattern withTemplate:(NSString *)withTemplate error:(NSError **)error {
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:pattern
options:NSRegularExpressionCaseInsensitive
error:error];
return [regex stringByReplacingMatchesInString:self
options:0
range:NSMakeRange(0, self.length)
withTemplate:withTemplate];
}
#end
resolve
NSString *string = #"123 &1245; Ross Test 12";
// remove all matches string
NSString *result = [string replacingWithPattern:#"&[\\d]+?;" withTemplate:#"" error:nil];
// result = "123 Ross Test 12"
or more
NSString *string = #"123 + 456";
// swap number
NSString *result = [string replacingWithPattern:#"([\\d]+)[ \\+]+([\\d]+)" withTemplate:#"$2 + $1" error:nil];
// result = 456 + 123
Swift2
extension String {
func replacing(pattern: String, withTemplate: String) throws -> String {
let regex = try NSRegularExpression(pattern: pattern, options: .CaseInsensitive)
return regex.stringByReplacingMatchesInString(self, options: [], range: NSRange(0..<self.utf16.count), withTemplate: withTemplate)
}
}
Swift3
extension String {
func replacing(pattern: String, withTemplate: String) throws -> String {
let regex = try RegularExpression(pattern: pattern, options: .caseInsensitive)
return regex.stringByReplacingMatches(in: self, options: [], range: NSRange(0..<self.utf16.count), withTemplate: withTemplate)
}
}
use
var string = "1!I 2\"want 3#to 4$remove 5%all 6&digit and a char right after 7'from 8(string"
do {
let result = try string.replacing("[\\d]+.", withTemplate: "")
} catch {
// error
}
// result = "I want to remove all digit and a char right after from string"
I'm trying to detect the text in a text view whether it contains anything beyond a pattern of hex value \u00 - \u7f or not and then do something. Please take a look at this code:
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[\x00-\x7f]"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSRange rangeOfFirstMatch = [regex rangeOfFirstMatchInString:textView.text
options:0
range:NSMakeRange(0, [textView.text length])];
if (!NSEqualRanges(rangeOfFirstMatch, NSMakeRange(NSNotFound, 0)))
{
// do statement 1
}
else
{
// do statement 2
}
From above, if the text view contains both text inside and outside [\u00 - \u7f] this will do statement 1 but what I want is do statement 2.
In my opinion, it should have the regular expression opposite to this pattern but I don't know what it is. Any suggestions are welcome, thank you.
A carat ('^') negates a character class, so [^\u00-\u7f] will match any character except those in the range '\u00' through '\u7f'.
You could also use rangeOfCharacterFromSet: or canBeConvertedToEncoding: to check whether a string has any non-ASCII characters.
rangeOfCharacterFromSet:
NSRange ASCIIRange = NSMakeRange(0, 0x80);
NSCharacterSet *nonASCIICharSet = [[NSCharacterSet characterSetWithRange:ASCIIRange] invertedSet];
NSRange nonASCIIChars = [textView.text rangeOfCharacterFromSet:nonASCIICharSet];
if (nonASCIIChars.location == NSNotFound) {
...
} else {
// textView.text contains non-ASCII characters
...
}
canBeConvertedToEncoding:
if ([textView.text canBeConvertedToEncoding:NSASCIIStringEncoding]) {
...
} else {
// textView.text contains non-ASCII characters
...
}
I'm looking for a simple, efficient way to convert strings in CamelCase to underscore notation (i.e., MyClassName -> my_class_name) and back again in Objective C.
My current solution involves lots of rangeOfString, characterAtIndex, and replaceCharactersInRange operations on NSMutableStrings, and is just plain ugly as hell :) It seems that there must be a better solution, but I'm not sure what it is.
I'd rather not import a regex library just for this one use case, though that is an option if all else fails.
Chris's suggestion of RegexKitLite is good. It's an excellent toolkit, but this could be done pretty easily with NSScanner. Use -scanCharactersFromSet:intoString: alternating between +uppercaseLetterCharacterSet and +lowercaseLetterCharacterSet. For going back, you'd use -scanUpToCharactersFromSet: instead, using a character set with just an underscore in it.
How about these:
NSString *MyCamelCaseToUnderscores(NSString *input) {
NSMutableString *output = [NSMutableString string];
NSCharacterSet *uppercase = [NSCharacterSet uppercaseLetterCharacterSet];
for (NSInteger idx = 0; idx < [input length]; idx += 1) {
unichar c = [input characterAtIndex:idx];
if ([uppercase characterIsMember:c]) {
[output appendFormat:#"_%#", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
} else {
[output appendFormat:#"%C", c];
}
}
return output;
}
NSString *MyUnderscoresToCamelCase(NSString *underscores) {
NSMutableString *output = [NSMutableString string];
BOOL makeNextCharacterUpperCase = NO;
for (NSInteger idx = 0; idx < [underscores length]; idx += 1) {
unichar c = [underscores characterAtIndex:idx];
if (c == '_') {
makeNextCharacterUpperCase = YES;
} else if (makeNextCharacterUpperCase) {
[output appendString:[[NSString stringWithCharacters:&c length:1] uppercaseString]];
makeNextCharacterUpperCase = NO;
} else {
[output appendFormat:#"%C", c];
}
}
return output;
}
Some drawbacks are that they do use temporary strings to convert between upper and lower case, and they don't have any logic for acronyms, so myURL will result in my_u_r_l.
Try this magic:
NSString* camelCaseString = #"myBundleVersion";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(?<=[a-z])([A-Z])|([A-Z])(?=[a-z])" options:0 error:nil];
NSString *underscoreString = [[regex stringByReplacingMatchesInString:camelCaseString options:0 range:NSMakeRange(0, camelCaseString.length) withTemplate:#"_$1$2"] lowercaseString];
NSLog(#"%#", underscoreString);
Output: my_bundle_version
If your concern is just the visibility of your code, you could make a category for NSString using the methods you've designed already. That way, you only see the ugly mess once. ;)
For instance:
#interface NSString(Conversions) {
- (NSString *)asCamelCase;
- (NSString *)asUnderscored;
}
#implementation NSString(Conversions) {
- (NSString *)asCamelCase {
// whatever you came up with
}
- (NSString *)asUnderscored {
// whatever you came up with
}
}
EDIT: After a quick Google search, I couldn't find any way of doing this, even in plain C. However, I did find a framework that could be useful. It's called RegexKitLite. It uses the built-in ICU library, so it only adds about 20K to the final binary.
Here's my implementation of Rob's answer:
#implementation NSString (CamelCaseConversion)
// Convert a camel case string into a dased word sparated string.
// In case of scanning error, return nil.
// Camel case string must not start with a capital.
- (NSString *)fromCamelCaseToDashed {
NSScanner *scanner = [NSScanner scannerWithString:self];
scanner.caseSensitive = YES;
NSString *builder = [NSString string];
NSString *buffer = nil;
NSUInteger lastScanLocation = 0;
while ([scanner isAtEnd] == NO) {
if ([scanner scanCharactersFromSet:[NSCharacterSet lowercaseLetterCharacterSet] intoString:&buffer]) {
builder = [builder stringByAppendingString:buffer];
if ([scanner scanCharactersFromSet:[NSCharacterSet uppercaseLetterCharacterSet] intoString:&buffer]) {
builder = [builder stringByAppendingString:#"-"];
builder = [builder stringByAppendingString:[buffer lowercaseString]];
}
}
// If the scanner location has not moved, there's a problem somewhere.
if (lastScanLocation == scanner.scanLocation) return nil;
lastScanLocation = scanner.scanLocation;
}
return builder;
}
#end
Here's yet another version based on all the above. This version handles additional forms. In particular, tested with the following:
camelCase => camel_case
camelCaseWord => camel_case_word
camelURL => camel_url
camelURLCase => camel_url_case
CamelCase => camel_case
Here goes
- (NSString *)fromCamelCaseToDashed3 {
NSMutableString *output = [NSMutableString string];
NSCharacterSet *uppercase = [NSCharacterSet uppercaseLetterCharacterSet];
BOOL previousCharacterWasUppercase = FALSE;
BOOL currentCharacterIsUppercase = FALSE;
unichar currentChar = 0;
unichar previousChar = 0;
for (NSInteger idx = 0; idx < [self length]; idx += 1) {
previousChar = currentChar;
currentChar = [self characterAtIndex:idx];
previousCharacterWasUppercase = currentCharacterIsUppercase;
currentCharacterIsUppercase = [uppercase characterIsMember:currentChar];
if (!previousCharacterWasUppercase && currentCharacterIsUppercase && idx > 0) {
// insert an _ between the characters
[output appendString:#"_"];
} else if (previousCharacterWasUppercase && !currentCharacterIsUppercase) {
// insert an _ before the previous character
// insert an _ before the last character in the string
if ([output length] > 1) {
unichar charTwoBack = [output characterAtIndex:[output length]-2];
if (charTwoBack != '_') {
[output insertString:#"_" atIndex:[output length]-1];
}
}
}
// Append the current character lowercase
[output appendString:[[NSString stringWithCharacters:¤tChar length:1] lowercaseString]];
}
return output;
}
If you are concerned with the speed of your code you probably want to write a more performant version of the code:
- (nonnull NSString *)camelCaseToSnakeCaseString {
if ([self length] == 0) {
return #"";
}
NSMutableString *output = [NSMutableString string];
NSCharacterSet *digitSet = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *uppercaseSet = [NSCharacterSet uppercaseLetterCharacterSet];
NSCharacterSet *lowercaseSet = [NSCharacterSet lowercaseLetterCharacterSet];
for (NSInteger idx = 0; idx < [self length]; idx += 1) {
unichar c = [self characterAtIndex:idx];
// if it's the last one then just append lowercase of character
if (idx == [self length] - 1) {
if ([uppercaseSet characterIsMember:c]) {
[output appendFormat:#"%#", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else {
[output appendFormat:#"%C", c];
}
continue;
}
unichar nextC = [self characterAtIndex:(idx+1)];
// this logic finds the boundaries between lowercase/uppercase/digits and lets the string be split accordingly.
if ([lowercaseSet characterIsMember:c] && [uppercaseSet characterIsMember:nextC]) {
[output appendFormat:#"%#_", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else if ([lowercaseSet characterIsMember:c] && [digitSet characterIsMember:nextC]) {
[output appendFormat:#"%#_", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else if ([digitSet characterIsMember:c] && [uppercaseSet characterIsMember:nextC]) {
[output appendFormat:#"%#_", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else {
// Append lowercase of character
if ([uppercaseSet characterIsMember:c]) {
[output appendFormat:#"%#", [[NSString stringWithCharacters:&c length:1] lowercaseString]];
}
else {
[output appendFormat:#"%C", c];
}
}
}
return output;
}
I have combined the answers found here into my refactoring library, es_ios_utils. See NSCategories.h:
#property(nonatomic, readonly) NSString *asCamelCaseFromUnderscores;
#property(nonatomic, readonly) NSString *asUnderscoresFromCamelCase;
Usage:
#"my_string".asCamelCaseFromUnderscores
yields #"myString"
Please push improvements!
I happened upon this question looking for a way to convert Camel Case to a spaced, user displayable string. Here is my solution which worked better than replacing #"_" with #" "
- (NSString *)fromCamelCaseToSpaced:(NSString*)input {
NSCharacterSet* lower = [NSCharacterSet lowercaseLetterCharacterSet];
NSCharacterSet* upper = [NSCharacterSet uppercaseLetterCharacterSet];
for (int i = 1; i < input.length; i++) {
if ([upper characterIsMember:[input characterAtIndex:i]] &&
[lower characterIsMember:[input characterAtIndex:i-1]])
{
NSString* soFar = [input substringToIndex:i];
NSString* left = [input substringFromIndex:i];
return [NSString stringWithFormat:#"%# %#", soFar, [self fromCamelCaseToSpaced:left]];
}
}
return input;
}
OK guys. Here is an all regex answer, which I consider the only true way:
Given:
NSString *MYSTRING = "foo_bar";
NSRegularExpression *_toCamelCase = [NSRegularExpression
regularExpressionWithPattern:#"(_)([a-z])"
options:NSRegularExpressionCaseInsensitive error:&error];
NSString *camelCaseAttribute = [_toCamelCase
stringByReplacingMatchesInString:MYSTRING options:0
range:NSMakeRange(0, attribute.length)
withTemplate:#"\\U$2"];
Yields fooBar.
Conversely:
NSString *MYSTRING = "fooBar";
NSRegularExpression *camelCaseTo_ = [NSRegularExpression
regularExpressionWithPattern:#"([A-Z])"
options:0 error:&error];
NSString *underscoreParsedAttribute = [camelCaseTo_
stringByReplacingMatchesInString:MYSTRING
options:0 range:NSMakeRange(0, attribute.length)
withTemplate:#"_$1"];
underscoreParsedAttribute = [underscoreParsedAttribute lowercaseString];
Yields: foo_bar.
\U$2 replaces second capture group with upper-case version of itself :D
\L$1 however, oddly, does not replace the first capture group with a lower-case version of itself :( Not sure why, it should work. :/