Maybe I'm going nuts, but I can't seem to understand why isEqualToString is returning false in this case.
I have written the following method to decode strings from percent encoded URL:
-(NSString*) decodeFromURLSafe: (NSString*) urlToDecode{
NSString *safeUrl = [urlToDecode stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
safeUrl = [safeUrl stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return safeUrl;
}
In practice it works, but I wrote some tests for it and don't understand why they are failing
Here's one such test:
-(void)testDecodingFromURLSafe{
NSString *unescapedString = #"#a!b*c(d)e;f:g&h=i+j$k,l/m#n\\p[q]r<s>t^u{v}w|x~y";
NSString *answer = [_viewController decodeFromURLSafe:#"%40a%21b%2Ac%28d%29e%3Bf%3Ag%26h%3Di%2Bj%24k%2Cl%2Fm%23n%5C%5Cp%5Bq%5Dr%3Cs%3Et%5Eu%7Bv%7Dw%7Cx%7Ey"];
NSLog(#"%#", answer);
NSLog(#"%d", [answer isEqualToString:#"#a!b*c(d)e;f:g&h=i+j$k,l/m#n\\p[q]r<s>t^u{v}w|x~y"]);
XCTAssert([answer isEqualToString:unescapedString], #"decoding works");
}
The string in the second NSLog statement is copied directly from the output of the first:
2014-11-20 14:03:46.352 ProjName[5573:60b] #a!b*c(d)e;f:g&h=i+j$k,l/m#n\\p[q]r<s>t^u{v}w|x~y
But both the comparisons return false and I'm confused as to what I'm missing.
I've tried putting the string into DiffNow to double check that they're identical and still nothing.
You need to double your backslashes, so that they escape correctly:
#a!b*c(d)e;f:g&h=i+j$k,l/m#n\\\\p[q]r<s>t^u{v}w|x~y
Related
I want to have a percentage sign in my string after a digit. Something like this: 75%.
How can I have this done? I tried:
[NSString stringWithFormat:#"%d\%", someDigit];
But it didn't work for me.
The code for percent sign in NSString format is %%. This is also true for NSLog() and printf() formats.
The escape code for a percent sign is "%%", so your code would look like this
[NSString stringWithFormat:#"%d%%", someDigit];
Also, all the other format specifiers can be found at Conceptual Strings Articles
If that helps in some cases, it is possible to use the unicode character:
NSLog(#"Test percentage \uFF05");
The accepted answer doesn't work for UILocalNotification. For some reason, %%%% (4 percent signs) or the unicode character '\uFF05' only work for this.
So to recap, when formatting your string you may use %%. However, if your string is part of a UILocalNotification, use %%%% or \uFF05.
seems if %% followed with a %#, the NSString will go to some strange codes
try this and this worked for me
NSString *str = [NSString stringWithFormat:#"%#%#%#", #"%%",
[textfield text], #"%%"];
uese following code.
NSString *searchText = #"Bhupi"
NSString *formatedSearchText = [NSString stringWithFormat:#"%%%#%%",searchText];
will output: %Bhupi%
iOS 9.2.1, Xcode 7.2.1, ARC enabled
You can always append the '%' by itself without any other format specifiers in the string you are appending, like so...
int test = 10;
NSString *stringTest = [NSString stringWithFormat:#"%d", test];
stringTest = [stringTest stringByAppendingString:#"%"];
NSLog(#"%#", stringTest);
For iOS7.0+
To expand the answer to other characters that might cause you conflict you may choose to use:
- (NSString *)stringByAddingPercentEncodingWithAllowedCharacters:(NSCharacterSet *)allowedCharacters
Written out step by step it looks like this:
int test = 10;
NSString *stringTest = [NSString stringWithFormat:#"%d", test];
stringTest = [[stringTest stringByAppendingString:#"%"]
stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet alphanumericCharacterSet]];
stringTest = [stringTest stringByRemovingPercentEncoding];
NSLog(#"percent value of test: %#", stringTest);
Or short hand:
NSLog(#"percent value of test: %#", [[[[NSString stringWithFormat:#"%d", test]
stringByAppendingString:#"%"] stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet alphanumericCharacterSet]] stringByRemovingPercentEncoding]);
Thanks to all the original contributors. Hope this helps. Cheers!
This question already has answers here:
Split an NSString to access one particular piece
(7 answers)
Closed 9 years ago.
I want to filter string after character '='. For eg if 8+9=17 My output should be 17. I can filter character before '=' using NSScanner, how to do its reverse??? I need a efficient way to do this without using componentsSeparatedByString or creating an array
Everyone seems to like to use componentsSeparatedByString but it is quite inefficient when you just want one part of a string.
Try this:
NSString *str = #"8+9=17";
NSRange equalRange = [str rangeOfString:#"=" options:NSBackwardsSearch];
if (equalRange.location != NSNotFound) {
NSString *result = [str substringFromIndex:equalRange.location + equalRange.length];
NSLog(#"The result = %#", result);
} else {
NSLog(#"There is no = in the string");
}
Update:
Note - for this specific example, the difference in efficiencies is negligible if it is only being done once.
But in general, using componentsSeparatedByString: is going to scan the entire string looking for every occurrence of the delimiter. It then creates an array with all of the substrings. This is great when you need most of those substrings.
When you only need one part of a larger string, this is very wasteful. There is no need to scan the entire string. There is no need to create an array. There is no need to get all of the other substrings.
NSArray * array = [string componentsSeparatedByString:#"="];
if (array)
{
NSString * desiredString = (NSString *)[array lastObject]; //or whichever the index
}
else
{
NSLog(#""); //report error - = not found. Of array could somehow be not created.
}
NOTE:
Though this is very popular splitting solution, it is only worth trying whenever every substring separated by separator string is required. rmaddy's answer suggest better mechanism whenever the need is only to get small part of the string. Use that instead of this approach whenever only small part of the string is required.
Try to use this one
NSArray *arr = [string componentsSeparatedByString:#"="];
if (arr.count > 0)
{
NSString * firstString = [arr objectAtIndex:0];
NSString * secondString = [arr objectAtIndex:1];
NSLog(#"First String %#",firstString);
NSLog(#"Second String %#",secondString);
}
Output
First String 8+9
Second String 17
Use this:
NSString *a =#"4+6=10";
NSLog(#"%#",[a componentsSeparatedByString:#"="])
;
Log: Practice[7582:11303] (
"4+6",
10
)
While working on project code left to me by a previous dev, I have encountered the following construct
-(NSString *)StringCheckWithString:(NSString *)string{
NSString *string2 = [NSString stringWithFormat:#"%#", string];
if([string2 length] == 0){
return #"none";
}
else {
return string2;
}
}
Can anyone explain why you would do this, it seems significantly overengineered to me and I don't understand why it has been done this way (for clarity, I don't understand why the string is formatted like this, I understand the length check)
The argument that is passed in could be any subclass of string, including NSMutableString. This code creates an immutable copy of it. This means that you can store the returned string without having to worry about someone else modifying it.
A better way of doing this would be:
NSString *string2 = [string copy];
According to the NSCopying Protocol reference:
The copy returned is immutable if the consideration “immutable vs.
mutable” applies to the receiving object.
I am working on the infamous Stanford calculator assignment. I need to verify inputted numbers for valid float values, so we can handle numbers like 102.3.79.
To avoid having to write a little loop to count periods in the string, there's got to be a built-in function yeah?
You can use the C standard library function strtod(). It stops where it encounters an error, and sets its output argument accordingly. You can exploit this fact as follows:
- (BOOL)isValidFloatString:(NSString *)str
{
const char *s = str.UTF8String;
char *end;
strtod(s, &end);
return !end[0];
}
There's at least one fairly elegant solution for counting #"." in a string:
NSString *input = #"102.3.79";
if([[input componentsSeparatedByString:#"."] count] > 2) {
NSLog(#"input has too many points!");
}
Digging a little deeper... If you're looking to validate the whole string as a number, try configuring an NSNumberFormatter and call numberFromString: (NSNumberFormatter documentation).
Having gone through CS193P, I think the idea is to get comfortable with NSString and UILabel versus using C. I would look into having a simple decimal point BOOL flag, as buttons are pressed and you are concatenating the numbers 1- for use and 2- for display.
This will come in handy as well when you are doing other checks like hanging decimal points at the end of the number or allowing the user to backspace a number.
Edited for example:
Create an IBAction connected to each number button:
- (IBAction)numberButtonPressed:(UIButton *)sender
{
if([sender.titleLabel.text isEqualToString:#"."])
{
if (!self.inTheMiddleOfEnteringANumber)
self.display.text=[NSString stringWithString:#"0."];
else if (!self.decimalPointEntered)
{
self.display.text=[self.display.text stringByAppendingString:sender.titleLabel.text];
self.decimalPointEntered=TRUE;
}
}
self.inTheMiddleOfEnteringANumber=TRUE;
}
-(BOOL) isNumeric:(NSString*)string {
NSNumberFormatter *formatter = [NSNumberFormatter new];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber *number = [formatter numberFromString:string];
[formatter release]; // if using ARC remove this line
return number!=nil;
}
-(BOOL) isFloat:(NSString*)string {
NSScanner *scanner = [NSScanner scannerWithString:string];
[scanner scanFloat:NULL];
return [scanner isAtEnd];
}
I have a NSSring:
NSString *example = #"'example01','example02','example03','example04'";
How can I make from this line NSArray?
NSString *example = [example stringByReplacingOccurrencesOfString:#"'" withString:#""];
NSArray * exampleArr = [example componentsSeparatedByString:#","];
NSArray *commaSeparatedComponents = [example componentsSeparatedByString:#","];
NSCharacterSet *quotesSet = [NSCharacterSet characterSetWithCharactersInString:#"'"];
for (NSString *component in commaSeparatedComponents) {
NSString *correctlyTrimmedComponent = [component stringByTrimmingCharactersInSet:quotesSet]; // only remove 's at the edges
// ... do something with each component; maybe add to a mutable array ...
}
This has the advantage over the other answer to not remove quotes that exist inside the values, but it doesn't do anything to actually solve quotes escaping that might have been necessary inside the data, and so on. It still misbehaves with some strings, but it misbehaves for fewer cases because it is less flippant about which quotes it removes.
If this is anything above and beyond a string in that exact format, you will probably need a parser for this sort of string that can handle the semantics of how the quotes are escaped, gracefully handles garbage, etc.