How to handle spaces in search term - ios

I am implementing a search using the following code snippet.
-(void)getData:(NSString *)searchString
{
//Search string is the string the user keys in as keywords for the search. In this case I am testing with the keywords "epic headline"
searchString = [searchString stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *resourcePath = [NSString stringWithFormat:#"/sm/search?limit=100&term=%#&types[]=users&types[]=questions&types[]=topics",searchString];
[self sendRequests:resourcePath];
}
//URL sent to server as a result
send Request /sm/search?limit=100&term=epic headline&types[]=users&types[]=questions&types[]=topics
My search is not working as it is unable to handle the space between 'epic' and 'headline'. How can I modify the search term so that the spacing can be handled?

Call stringByAddingPercentEscapesUsingEncoding on the result string to encode space characters as requiredby the rules of URLs.

Related

url encoding issue in iOS7

I am having a link that i want to post the data.
I am using url encoding like,
http://admin:testsite#www.arabcircleonline.com/index.php?%#=%#",form_urlencode_rfc3986(#"do"),form_urlencode_rfc3986(#"/webservice/whisper/login_chauhankevalp#gmail.com/password_keval/action_whisper/whisperdata_{\"user_status\":\"last123\",\"privacy\":0,\"privacy_comment\":0}
This is giving the response intended when a record should be added, but the record is not getting added, when i execute this link on browser, it works fine.
Please help me out of this.. i am working on this last 2 days with no solution
form_urlencode_rfc3986 method i am using is,
NSString* form_urlencode_rfc3986(NSString* s) {
CFStringRef charactersToLeaveUnescaped = CFSTR(" ");
CFStringRef legalURLCharactersToBeEscaped = CFSTR("/%&=?$#+-~#<>|\\*,.()[]{}^!");
NSString *result = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes( kCFAllocatorDefault,(__bridge CFStringRef)s,charactersToLeaveUnescaped,legalURLCharactersToBeEscaped, kCFStringEncodingUTF8));
return [result stringByReplacingOccurrencesOfString:#" " withString:#"+"];
}
You are probably trying to do this:
You have a url with a query. The query component is separated by a "?" as illustrated below:
URL := scheme-authority-path "?" query
In your case "scheme-authority-path" is
http://admin:testsite#www.arabcircleonline.com/index.php,
and a "query" is a list of parameters, separated by a "&".
Your URL string without query (scheme, authority and path):
NSString* urlString = #"http://admin:testsite#www.arabcircleonline.com/index.php";
Compose a parameter (which is part of the query), e.g. in BNF
parameter := name "=" value
NOTE: name and value need to be encoded with the helper function.
which corresponds in code:
NSString* parameterString = [NSString stringWithFormat:#"%#=%#",
form_urlencode_rfc3986(#"do"),
form_urlencode_rfc3986(
#"/webservice/whisper/login_chauhankevalp#gmail.com/password_keval/action_whisper/whisperdata_{\"user_status\":\"last123\",\"privacy\":0,\"privacy_comment\":0")
];
A query string is composed by concatenating (encoded) parameters and separating them by a "&", e.g. in BNF:
query := parameter ["&" parameter]
You have only one parameter, thus our query string becomes just the parameter string:
NSString* queryString = parameterString;
Now, compose the complete url string (including the query) from the former urlString (scheme, authority and path) and the query, by concatenating urlString, a "?" and the query. For example:
NSString* urlStringWithQuery = [NSString stringWithFormat:#"%#?%#", urlString, queryString];

String search with Turkish dotless i

When searching the text Çınaraltı Café for the text Ci using the code
NSStringCompareOptions options =
NSCaseInsensitiveSearch |
NSDiacriticInsensitiveSearch |
NSWidthInsensitiveSearch;
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:#"tr"];
NSRange range = [haystack rangeOfString:needle
options:options
range:NSMakeRange(o, haystack.length)
locale:locale];
I get range.location equals NSNotFound.
It's not to do with the diacritic on the initial Ç because I get the same result searching for alti where the only odd character is the ı. I also get a valid match searching for Cafe which contains a diacritic (the é).
The apple docs mention this situation as notes on the locale parameter and I think I'm following them. Though I guess I'm not because it's not working.
How can I get a search for 'i' to match both 'i' and 'ı'?
I don't know whether this helps as an answer, but perhaps explains why it's happening.
I should point out I'm not an expert in this matter, but I've been looking into this for my own purposes and been doing some research.
Looking at the Unicode collation chart for latin, the equivalent characters to ASCII "i" (\u0069) do not include "ı" (\u0131), whereas all the other letters in your example string are as you expect, i.e.:
"c" (\u0063) does include "Ç" (\u00c7)
"e" (\u0065) does include "é" (\u00e9)
The ı character is listed separately as being of primary difference to i. That might not make sense to a Turkish speaker (I'm not one) but it's what Unicode have to say about it, and it does fit the logic of the problem you describe.
In Chrome you can see this in action with an in-page search. Searching in the page for ASCII i highlights all the characters in its block and does not match ı. Searching for ı does the opposite.
By contrast, MySQL's utf8_general_ci collation table maps uppercase ASCII I to ı as you want.
So, without knowing anything about iOS, I'm assuming it's using the Unicode standard and normalising all characters to latin by this table.
As to how you match Çınaraltı with Ci - if you can't override the collation table then perhaps you can just replace i in your search strings with a regular expression, so you search on Ç[iı] instead.
I wrote a simple extension in Swift 3 for Turkish string search.
let turkishSentence = "Türkçe ya da Türk dili, batıda Balkanlar’dan başlayıp doğuda Hazar Denizi sahasına kadar konuşulan Altay dillerinden biridir."
let turkishWannabe = "basLayip"
let shouldBeTrue = turkishSentence.contains(turkishString: turkishWannabe, caseSensitive: false)
let shouldBeFalse = turkishSentence.contains(turkishString: turkishWannabe, caseSensitive: true)
You can check it out from https://github.com/alpkeser/swift_turkish_string_search/blob/master/TurkishTextSearch.playground/Contents.swift
I did this and seems to work well for me.. hope it helps!
NSString *cleanedHaystack = [haystack stringByReplacingOccurrencesOfString:#"ı"
withString:#"i"];
cleanedHaystack = [cleanedHaystack stringByReplacingOccurrencesOfString:#"İ"
withString:#"I"];
NSString *cleanedNeedle = [needle stringByReplacingOccurrencesOfString:#"ı"
withString:#"i"];
cleanedNeedle = [cleanedNeedle stringByReplacingOccurrencesOfString:#"İ"
withString:#"I"];
NSUInteger options = (NSDiacriticInsensitiveSearch |
NSCaseInsensitiveSearch |
NSWidthInsensitiveSearch);
NSRange range = [cleanedHaystack rangeOfString:cleanedNeedle
options:options];
As Tim mentions, we can use regular expression to match text containing i or ı. I also didn't want to add a new field or change the source data as the search looks up huge amounts of string. So I ended up a solution using regular expressions and NSPredicate.
Create NSString category and copy this method. It returns basic or matching pattern. You can use it with any method that accepts regular expression pattern.
- (NSString *)zst_regexForTurkishLettersWithCaseSensitive:(BOOL)caseSensitive
{
NSMutableString *filterWordRegex = [NSMutableString string];
for (NSUInteger i = 0; i < self.length; i++) {
NSString *letter = [self substringWithRange:NSMakeRange(i, 1)];
if (caseSensitive) {
if ([letter isEqualToString:#"ı"] || [letter isEqualToString:#"i"]) {
letter = #"[ıi]";
} else if ([letter isEqualToString:#"I"] || [letter isEqualToString:#"İ"]) {
letter = #"[Iİ]";
}
} else {
if ([letter isEqualToString:#"ı"] || [letter isEqualToString:#"i"] ||
[letter isEqualToString:#"I"] || [letter isEqualToString:#"İ"]) {
letter = #"[ıiIİ]";
}
}
[filterWordRegex appendString:letter];
}
return filterWordRegex;
}
So if the search word is Şırnak, it creates Ş[ıi]rnak for case sensitive and Ş[ıiIİ]rnak for case insensitive search.
And here are the possible usages.
NSString *testString = #"Şırnak";
// First create your search regular expression.
NSString *searchWord = #"şır";
NSString *searchPattern = [searchWord zst_regexForTurkishLettersWithCaseSensitive:NO];
// Then create your matching pattern.
NSString *pattern = searchPattern; // Direct match
// NSString *pattern = [NSString stringWithFormat:#".*%#.*", searchPattern]; // Contains
// NSString *pattern = [NSString stringWithFormat:#"\\b%#.*", searchPattern]; // Begins with
// NSPredicate
// c for case insensitive, d for diacritic insensitive
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self matches[cd] %#", pattern];
if ([predicate evaluateWithObject:testString]) {
// Matches
}
// If you want to filter an array of objects
NSArray *matchedCities = [allAirports filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:#"city matches[cd] %#", pattern]];
You can also use NSRegularExpression but I think using case and diacritic insensitive search with NSPredicate is much more simpler.

How to properly form the requestString for a POST NSUrlRequest on iOS when array values are involved?

I need to form a POST NSURLRequest and I need to pass into the request this structure:
inspection (an array of NSDictionaries with string keys and values)
property (same structure as array1)
subcategories (an array of NSDictionaries where each dictionary can have an array of values for a certain key)
Here is how my requestString looks like after I concat everything:
?inspection[name]=inspection_name&inspection[address]=address_value&...&property[type]=property_type&....&subcategories[0][questions][0][title]=title_value&subcategories[0][questions][1][title]=title_value1&...&subcategories[1][questions][0][title]=title_valuen&...
For inspection and property array I've also tried inspection[][name]=inspection_name, property[][address]=property_address
While I'm forming that requestString I'm escaping each parameter using this method:
static NSString *escapeParam(NSString *param) {
param = [param stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
param = [param stringByReplacingOccurrencesOfString:#"&" withString:#"%26"];
param = [param stringByReplacingOccurrencesOfString:#"=" withString:#"%3D"];
param = [param stringByReplacingOccurrencesOfString:#"?" withString:#"%3F"];
return param;
}
There fore something like subcategories[0][questions][0][title]=title_value becomes subcategories%5B0%5D%5Bquestions%5D%5B0%5D%5Btitle%5D=title_value
Obviously I'm doing something wrong and don't know how to properly form this requestString because when I fire the request I get HTTP Error 400 Bad request in response.
Can someone point me in the right direction?
Thanks a bunch!
First of all &,=,? don't need to be encoded, these chars are supported.
Second of all, you don't need to add stringByAddingPercentEscapesUsingEncoding to the whole body, I think you don't need to add it at all because the server should support escaping chars. If the server doesn't support escaping chars, you should apply the stringByAddingPercentEscapesUsingEncoding only on the values, the keys should be as tehy are, something like
inspection[][name]=[inspection_name stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
This will handle eventual escaping chars from your values, but the keys should't have escaping characters since they are created to work on the server.

NSString separation-iOS

I have following strings. But I need to separate them by this "jsonp1343930692" and assign them NSString again. How could I that? I could able to separate them to NSArray but I don't know how to separate to NSString.
jsonp1343930692("snapshot":[{"timestamp":1349143800,"data":[{"label_id":10,"lat":29.7161,"lng":-95.3906,"attr":{"ozone_level":37,"exp":"IN","gridpoint":"29.72:-95.39"}},{"label_id":10,"lat":30.168456,"lng":-95.50448}]}]})
jsonp1343930692("snapshot":[{"timestamp":1349144700,"data":[{"label_id":10,"lat":29.7161,"lng":-95.3906,"attr":{"ozone_level":37,"exp":"IN","gridpoint":"29.72:-95.39"}},{"label_id":10,"lat":30.168456,"lng":-95.50448,"attr":{"ozone_level":57,"exp":"IN","gridpoint":"30.17:-95.5"}},{"label_id":10,"lat":29.036944,"lng":-95.438333}]}]})
The jsonp1343930692 prefix in your string is odd: I don't know where you string come from, but it really seems to be some JSON string with this strange prefix that has no reason to be there. The best shot here is probably to check if it is normal to have this prefix, for example if you get this string from a WebService it is probably the WebService fault to return this odd prefix.
Anyway, if you want to remove the jsonp1343930692 prefix of your string, you have multiple options:
Check that the prefix is existant, and if so, remove the right number of characters from the original string:
NSString* str = ... // your string with the "jsonp1343930692" prefix
static NSString* kStringToRemove = #"jsonp1343930692";
if ([str hasPrefix:kStringToRemove])
{
// rebuilt a string by only using the substring after the prefix
str = [str substringFromIndex:kStringToRemove.length];
}
Split your string in multiple parts, using the jsonp1343930692 string as a separator
NSString* str = ... // your string with the "jsonp1343930692" prefix
static NSString* kStringToRemove = #"jsonp1343930692";
NSArray* parts = [str componentsSeparatedByString:kStringToRemove];
str = [parts componentsJoinedByString:#""];
Replace every occurrences of jsonp1343930692 by the empty string.
NSString* str = ... // your string with the "jsonp1343930692" prefix
static NSString* kStringToRemove = #"jsonp1343930692";
str = [str stringByReplacingOccurrencesOfString:kStringToRemove withString:#""];
So in short you have many possibilities depending on what exactly you want to do :)
Of course, once you have removed your strange jsonp1343930692 prefix, you can deserialize your JSON string to obtain a JSON object (either using some third-party lib like SBJSON or using NSJSONSerializer on iOS5 and later, etc)
Have a look at the NSJSONSerialization class to turn this into a Cocoa collection that you can deal with.

Search NSString in line from file

Is it possible to make a function that searchs a string for an exact substring so that it will only 'return true' if the exact string if found, not as part of a larger word?
NSString* search = #"tele";
NSString* stringOne = #"telephone";
NSString* stringTwo = #"tele phone";
NSString* stringThree = #"phone tele";
What I mean is: Is it possible to search for a string in a way that the NSString 'search' would be found in strings Two and Three, but not One?
Try using the following function in the NSString class:
- (NSRange)rangeOfString:(NSString *)aString
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsstring_Class/Reference/NSString.html
Simplest approach is to append blanks (or whatever your separators are) to front and rear of both strings, then do the search.

Resources