Problem using NSString compare:options:range, conflicting results - iphone

Ohh, what is wrong with this code !?!?!
NSString *s1 = #"5 Oct 2010 18:30";
NSString *s2 = #"5 Oct 2010 09:47";
NSRange range = {0, 11}; // Both "D MMM YYYY " and "DD MMM YYYY"
NSComparisonResult result = 0;
result = [s1 compare:s2 options:NSLiteralSearch range:range];
// result == -1
NSString *sa = [s1 substringWithRange:range];
NSString *sb = [s2 substringWithRange:range];
result = [sa compare:sb];
// result == 0
Why do I get different results from those two comperes? As far as I can tell, they should be same?

Here's a better answer, thanks to the kind people at the CocoaDev mailing list!
The 'range' referred to in the method signature is the range of the receiving string only.
So, in your first example, you are comparing the characters in range of s1 with the whole of s2; and that, correctly, is reported as -1.
This explains the apparent anomaly noted by fluchtpunkt, as well.

There's nothing wrong with it; sa and sb have the same values, but s1 and s2 do not.
EDIT:
Sorry, read it too quickly. There is indeed a problem - see below.

Related

Objective C : Get correct float values(justified)

I worked a lot in it and can't find a solution. Even the title can't explain clearly.
I have three values weight, quantity and total
I had done the following
float wq = [[weightarray objectAtIndex:selectedint]floatValue];
float q = [quantity floatValue];
float total = wq * q;
for ex, if
[weightarray objectAtIndex:selectedint] = #"3.14";
quantity = 4;
then the result is
wq = 3.140000 q= 4.000000 total = 12.560000
but I need
wq = 3.14 total = 12.56
what to do?
I searched a lot, someone suggests to use NSDecimal,
NSDecimalNumberHandler *roundingBehavior = [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:NSRoundPlain scale:2 raiseOnExactness:FALSE raiseOnOverflow:TRUE raiseOnUnderflow:TRUE raiseOnDivideByZero:TRUE];
but the scale is not 2 here, wq value may have 3 or four numbers after point.
If the total = 2.30000100 means I need total = 2.300001
how to solve this?
I'm not entirely sure what it is your asking for, but it seems as if you want the values to only display a 2 d.p. In which case you could use a string format like so:
NSString *output = [NSString stringWithFormat:#"float = %.2f", 3.14];
The .2 specifies that the float should be justified to 2 d.p.
Hope this helps
There may be a more direct way to achieve it (which I don't know) but here's a suggestion...
Convert to string as you already do.
Use [myString hasSuffix:#"0"] to see if it ends in zero.
Use [myString substringToindex:[myString length]-1] to create a new string without the final zero.
Repeat.
I know it's not elegant, but unless someone has a better solution, this will at least do what you want.
UPDATE: scratch that - I just discovered [myString stringByTrimmingCharactersInSet:set]. Surely this must be what you need...?
Finally solution found, thanks to Martin
float total = 12.56000;
NSString *s = [NSString stringWithFormat:#"%f", total];
NSLog(#"%#",s);
BOOL success;
success =NO;
while(!success)
{
if ([s hasSuffix:#"0"])
{
s = [s substringWithRange:NSMakeRange(0,[s length]-1)];
}
else if ([s hasSuffix:#"."])
{
s = [s substringWithRange:NSMakeRange(0,[s length]-1)];
success = YES;
}
else
success = YES;
}
NSLog(#"%#",s);
if total = 12.560000 it returns total = 12.56
if total = 12.000000 it returns total = 12
if total = 10.000000 it returns total = 10
if total = 12.3000100 it returns total = 12.30001

invalid operands to binary expression nsstring and id

hi i am getting the errer invalid operends to binary expression nsstring and id even i use typecasting this is the code in which i have problem . kindly correct this code.
for (int j = 0 ; j<newarray.count ; j++){
if(j<newarray.count){
message = (NSString *) message + [newarray objectAtIndex:j]+ "," ;
}
}
You can not use + operator with objects, for your specific case you may replace the whole cycle with:
NSString* message = [newarray componentsJoinedByString:#","];
And FIY Objective-C does not support operator overloading at all.
I'm not really sure if this was your intention, but if you were trying to append new information to the string separated by commas you could go with something like this:
for (int j = 0 ; j<newarray.count ; j++){
[message stringByAppendingString:[NSString stringWithFormat:#"%#,",[newarray objectAtIndex:j]]];
}
Additionally, your condition if(j<newarray.count) would always evaluate true in this loop, and is therefore unnecessary.
You seem to be assuming NSString acts like std::string in C++. Try this:
NSMutableString *message = ...;
for (unsigned j = 0; j < newarray.count; j++)
{
if (j > 0)
[message appendString:#", "];
[message appendString:[newarray objectAtIndex:j]];
}
You should cast "[newarray objectAtIndex:j]", whose default return type is "id"
Check this
Also IIRC NSString doesn't have + operand overloaded. So maybe you should try [NSString stringWithFormat:].

Validating the phone numbers

I want to have only 13 numeric values or the 13numeric values can be prefixed with "+" sysmbol.so the + is not mandatory
Example : 1234567891234
another example is : +1234567891234
Telephone number format should be international,Is there any Regex for phone number validation in iPhone
I have tried the above link , but this +1234545 but i want to have only 13 numarals or + can be prefixed with that 13 numerals.
Please let me know , what can i change it here
This is the code i tried
NSString * forNumeric = #"^\\+(?:[0-9] ?){6,14}[0-9]$";
BOOL isMatch = [[textFieldRounded text] isMatchedByRegex:forNumeric];
if (isMatch == YES){
NSLog(#"Matched");
}
else {
NSLog(#"Not matched");
}
NSString * regex = #"((07|00447|004407|\\+4407|\\+447)\\d{9})";
Having found the leading 0 or the leading +44 once, why search for it again?
Basic simplification leads to
NSString * regex = #"((07|00440?7|\\+440?7)\\d{9})";
then to
NSString * regex = #"((07|(00|\\+)440?7)\\d{9})";
then to
NSString * regex = #"((0|(00|\\+)440?)7\\d{9})";
but 00 isn't the only common dial prefix, 011 is used in the US and Canada.
Adding that, and turning the order round, gives:
NSString * regex = #"(^((0(0|11)|\\+)440?|0)7\\d{9}$)";
or preferably
NSString * regex = #"(^(?:(?:0(?:0|11)|\\+)(44)0?|0)(7\\d{9}$))";
allowing 00447, 011447, +447, 004407, 0114407, +4407, 07 at the beginning, and with non-capturing groups.
For wider input format matching, allowing various punctuation (hyphens, brackets, spaces) use
NSString * regex = #"(^\\(?(?:(?:0(?:0|11)\\)?[\\s-]?\\(?|\\+)(44)\\)?[\\s-]?\\(?(?:0\\)?[\\s-]?\\(?)?|0)(7\\d{9})$)";
Extract the 44 country code in $1 (null if number entered as 07...) and the 10-digit NSN in $2.
However, be aware that numbers beginning 070 and 076 (apart from 07624) are NOT mobile numbers.
The final pattern:
NSString * regex = #"(^\\(?(?:(?:0(?:0|11)\\)?[\\s-]?\\(?|\\+)(44)\\)?[\\s-]?\\(?(?:0\\)?[\\s-]?\\(?)?|0)(7([1-5789]\\d{2}|624)\\)?[\\s-]?\\d{6}))$)";
Extract the NSN in $2 then remove all non-digits from it for further processing.
^(\+?)(\d{13})$ should do the trick, escape the slashes for objective-C usage.
13 digits, with an options + prefix.
If you want to play with regexp expressions you can use services like this one for visual feedback, very handy.
NSString * forNumeric = #"^(\\+?)(\\d{13})$";
How about this?
NSString *forNumeric = #"\\+?[0-9]{6,13}";
NSPredicate *predicate;
predicate = [NSPredicate predicateWithFormat:#"self matches %#", forNumeric];
BOOL isMatch = [predicate evaluateWithObject:#"+1234567890123"];
if (isMatch) NSLog(#"Matched");
else NSLog(#"Not matched");
NSDataDetector *matchdetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypePhoneNumber
error:&error];
NSUInteger matchNumber = [matchdetector numberOfMatchesInString:string options:0 range:NSMakeRange(0, [string length])];
If you use UITextField then:
textField.dataDetectorTypes = UIDataDetectorTypePhoneNumber;
you could try using a NSDataDetector:
http://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSDataDetector_Class/Reference/Reference.html
available in iOS4+
The following is what I do for validating UK mobile numbers:
- (BOOL) isValidPhoneNumber
{
NSString * regex = #"((07|00447|004407|\\+4407|\\+447)\\d{9})";
NSPredicate *testPredicate = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", regex];
BOOL validationResult = [testPredicate evaluateWithObject: self];
return validationResult;
}
See if it helps you

Format a String in IPhone

I need to add space after every 4 characters in a string.. For example if the string is aaaaaaaa, i need to format it as aaaa aaaa. I tried the following code, but it doesn't work for me.
NSMutableString *currentFormattedString = [[NSMutableString alloc] initWithString:formattedString];
int count = [formattedString length];
for (int i = 0; i<count; i++) {
if ( i %4 == 0) {
[currentFormattedString insertString:#" " atIndex:i];
}
}
Can anyone help me with this?
You haven't said what isn't working with your code, so it's hard to know exactly what to answer. As a tip - in future questions don't just say "it isn't working", but state WHAT isn't working and HOW it isn't working. However...
NSMutableString *currentFormattedString = [[NSMutableString alloc] initWithString:formattedString];
int count = [formattedString length];
for (int i = 0; i<count; i++) {
if ( i %4 == 0) {
[currentFormattedString insertString:#" " atIndex:i];
}
}
You are inserting a space, but you are not then accounting for this in your index value. So, suppose your formattedString is aaaaaaaaaaaaaaaa
The first time through your loop, you will get to the 4th position and insert a space at i=4
aaaa aaaaaaaaaaaa
Now the next time you get to insert a space, i will be 8. But the 8th position in your currentFormattedString isn't where you think it will be
aaaa aaa aaaaaaaaa
Next time it will be another 4 characters along which still isn't where you think
aaaa aaa aa aaaaaaa
And so on
You have to take into account the inserted space which will affect the offset value.
NSString *text = [[NSString alloc] initWithString:#"aaaaaaaa"];
NSString *result = [[NSString alloc] init];
double count = text.length/4;
if (count>1) {
for (int i = 0; i<count; i++) {
result = [NSString stringWithFormat:#"%#%# ",result,[text substringWithRange:NSMakeRange(i*4, 4)]];
}
result = [NSString stringWithFormat:#"%#%# ",result,[text substringWithRange:NSMakeRange(((int)count)*4, text.length-((int)count)*4)]];
}
else result = text;
I found the following which formats a string to a telephone number format, but it looks like you could easily change it to support other formats
Telephone number string formatting
Nick Bull answered on the reasons why your method broke already.
IMHO the appropriate solution would be to use a while loop and do the loop increments yourself.
NSInteger i = 4; // first #" " should be inserted after the 4th (index = 3) char
while (i < count) {
[currentFormattedString insertString:#" " atIndex:i];
count ++; // you did insert #" " so the length of the string increased
i += 5; // you now must skip 5 (" 1234") characters
}

how to split a string on the iPhone?

I have got below value(dynamic) from the server:
drwxr-xr-x 9 0 0 4096 Jan 10 05:30 California
Now i want to get valu like this.
drwxr-xr-x
9
0
0
4096
Jan 10
05:30
California
Please help me for this question
you can try smth like this
NSArray* components = [initialString componentsSeparatedByString:#" "];
See NSString componentsSeparatedByString for your answer.
As others have mentioned, you can use NSString's member function componentsSeparatedByString: or componentsSeparatedByCharactersInSet:
As an alternative (for more powerful tokenizing), look into the Objective-C NSScanner class in the foundation framework of Mac OS X.
You could do something like this:
NSString *str = "drwxr-xr-x 9 0 ... ";
NSScanner *scanner = [NSScanner scannerWithString:str];
In order to obtain each token in string form, use NSScanner's scanUpToCharactersFromSet:intoString: member function.
NSString *token = [NSString string];
NSCharacterSet *div = [NSCharacterSet whitespaceCharacterSet];
[scanner scanUpToCharactersFromSet:div intoString:token];
// token now contains #"drwxr-xr-x"
Subsequent calls to the above would return 9, 0, and so on.
Note: the code above has not been tested.
[myStringValue componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
may be useful as well.
Use a regex: RegexKitLite.
This is a "complete example" of a way to use a regex to do what you want with a lot of explanation, so it's a bit of a long answer. The regex used is just one way to do this, and is "fairly permissive" in what it accepts. The example shows:
How to match more than "one line / directory" at once.
A possible way to handle different date formats (Jan 10 05:30 and Apr 30 2009)
How to create an "array of arrays" of matches.
Iterate over the matched array and create a NSDictionary based on the parsed results.
Create a "comma separated values" version of the results.
Note: The example splits up some of its long strings across multiple lines. A string literal in the form of #"string1 " #"string2" will be "automagically" concatenated by the compiler to form a string that is equivalent to #"string 1 string2". I note this only because this might look a bit unusual if you're not used to it.
#import <Foundation/Foundation.h>
#import "RegexKitLite.h"
int main(int argc, char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSString *stringToMatch =
#"drwxr-xr-x 9 0 0 4096 Jan 10 05:30 California\n"
#"-rw-r--r-- 1 johne staff 1335 Apr 30 2009 tags.m"; // A random entry from my machine with an "older" date.
NSString *regex =
#"(?m)^" // (?m) means: to "have ^ and $ match new line boundaries". ^ means: "Match the start of a line".
// Below,
// (...) means: "Capture for extraction the matched characters". Captures start at 1, capture 0 matches "everything the regex matched".
// [^\\p{Z}]+ says: "Match one or more characters that are NOT 'Separator' characters (as defined by Unicode, essentially white-space)".
// In essence, '[^\\p{Z}]+' matches "One or more non-white space characters."
// \\s+ says: Match one or more white space characters.
// ([^\\p{Z}]+)\\s+ means: Match, and capture, the non-white space characters, then "gobble up" the white-space characters after the match.
#"([^\\p{Z}]+)\\s+" // Capture 1 - Permission
#"([^\\p{Z}]+)\\s+" // Capture 2 - Links (per `man ls`)
#"([^\\p{Z}]+)\\s+" // Capture 3 - User
#"([^\\p{Z}]+)\\s+" // Capture 4 - Group
#"([^\\p{Z}]+)\\s+" // Capture 5 - Size
#"(\\w{1,3}\\s+\\d+\\s+(?:\\d+:\\d+|\\d+))\\s+" // Capture 6 - The "date" part.
// \\w{1,3} means: One to three "word-like" characters (ie, Jan, Sep, etc).
// \\d+ means: Match one or more "digit-like" characters.
// (?:...) means: Group the following, but don't capture the results.
// (?:.A.|.B.) (the '|') means: Match either A, or match B.
// (?:\\d+:\\d+|\\d+) means: Match either '05:30' or '2009'.
#"(.*)$"; // Capture 7 - Name. .* means: "Match zero or more of any character (except newlines). $ means: Match the end of the line.
// Use RegexKitLites -arrayOfCaptureComponentsMatchedByRegex to create an
// "array of arrays" composed of:
// an array of every match of the regex in stringToMatch, and for each match,
// an array of all the captures specified in the regex.
NSArray *allMatchesArray = [stringToMatch arrayOfCaptureComponentsMatchedByRegex:regex];
NSLog(#"allMatchesArray: %#", allMatchesArray);
// Here, we iterate over the "array of array" and create a NSDictionary
// from the results.
for(NSArray *lineArray in allMatchesArray) {
NSDictionary *parsedDictionary =
[NSDictionary dictionaryWithObjectsAndKeys:
[lineArray objectAtIndex:1], #"permission",
[lineArray objectAtIndex:2], #"links",
[lineArray objectAtIndex:3], #"user",
[lineArray objectAtIndex:4], #"group",
[lineArray objectAtIndex:5], #"size",
[lineArray objectAtIndex:6], #"date",
[lineArray objectAtIndex:7], #"name",
NULL];
NSLog(#"parsedDictionary: %#", parsedDictionary);
}
// Here, we use RegexKitLites -stringByReplacingOccurrencesOfRegex method to
// create a new string. We use it to essentially transform the original string
// in to a "comma separated values" version of the string.
// In the withString: argument, '$NUMBER' means: "The characters that were matched
// by capture group NUMBER."
NSString *commaSeparatedString = [stringToMatch stringByReplacingOccurrencesOfRegex:regex withString:#"$1,$2,$3,$4,$5,$6,$7"];
NSLog(#"commaSeparatedString:\n%#", commaSeparatedString);
[pool release];
pool = NULL;
return(0);
}
Compile and run with:
shell% gcc -Wall -Wmost -arch i386 -g -o regexExample regexExample.m RegexKitLite.m -framework Foundation -licucore
shell% ./regexExample
2010-01-14 00:10:38.868 regexExample[49409:903] allMatchesArray: (
(
"drwxr-xr-x 9 0 0 4096 Jan 10 05:30 California",
"drwxr-xr-x",
9,
0,
0,
4096,
"Jan 10 05:30",
California
),
(
"-rw-r--r-- 1 johne staff 1335 Apr 30 2009 tags.m",
"-rw-r--r--",
1,
johne,
staff,
1335,
"Apr 30 2009",
"tags.m"
)
)
2010-01-14 00:10:38.872 regexExample[49409:903] parsedDictionary: {
date = "Jan 10 05:30";
group = 0;
links = 9;
name = California;
permission = "drwxr-xr-x";
size = 4096;
user = 0;
}
2010-01-14 00:10:38.873 regexExample[49409:903] parsedDictionary: {
date = "Apr 30 2009";
group = staff;
links = 1;
name = "tags.m";
permission = "-rw-r--r--";
size = 1335;
user = johne;
}
2010-01-14 00:10:38.873 regexExample[49409:903] commaSeparatedString:
drwxr-xr-x,9,0,0,4096,Jan 10 05:30,California
-rw-r--r--,1,johne,staff,1335,Apr 30 2009,tags.m