reading unicode from sqlite and creating a NSString - sqlite

Im working on an iOS app where I need to store and retrieve from an SQLite DB, a representation of a NSString that has subscripts. I can create a NSString at compile time with a constant:
#"Br\u2082_CCl\u2084"
\u2082 is a 2 subscript, \u2084 is a 4 subscript. What im storing in the SQLite db is:
"Br\u2082_CCl\u2084"
But what I can not figure out how to do, is reconvert that back into an NSString. The data comes back from the db as a char * "Br\\u2082_CCl\\u2084" Stripping out the extra slash has made no difference in my feeble experiments. I need a way get that back into an NSString - Thanks!

You need one of the NSString stringWithCString class methods or the corresponding initWithCString instance methods.

I solved the problem like this - error checking removed for clarity -
the unicode string comes into the parameter stringEncoded from the db like:
"MgBr\u2082_CH\u2082Cl\u2082"
+(NSString *)decodeUnicodeBytes:(char *)stringEncoded {
unsigned int unicodeValue;
char *p, buff[5];
NSMutableString *theString;
NSString *hexString;
NSScanner *pScanner;
theString = [[[NSMutableString alloc] init] autorelease];
p = stringEncoded;
buff[4] = 0x00;
while (*p != 0x00) {
if (*p == '\\') {
p++;
if (*p == 'u') {
memmove(buff, ++p, 4);
hexString = [NSString stringWithUTF8String:buff];
pScanner = [NSScanner scannerWithString: hexString];
[pScanner scanHexInt: &unicodeValue];
[theString appendFormat:#"%C", unicodeValue];
p += 4;
continue;
}
}
[theString appendFormat:#"%c", *p];
p++;
}
return [NSString stringWithString:theString];
}

Related

Xcode - sql Select a single value does not work

In my app, I trying to get the single id from data base using the query:
SELECT _id FROM rules where codigo_rest = 2345
I am passing that query to the following function:
-(NSString *)selectIDrest:(NSString *)query{
NSString * retval;
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil)
== SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
int uniqueId = sqlite3_column_int(statement, 0);
NSLog(#"int %i",uniqueId);
retval = [NSString stringWithFormat:#"%d",uniqueId];
}
sqlite3_finalize(statement);
}
NSLog(#"%#",retval);
return retval;
}
but the retval is alway 0., while table content id is different (1,2,3,4 ...etc).
By NSlogs, I realize that while (sqlite3_step(statement) == SQLITE_ROW) is never executed.
What is my fault?
You are never executing the query, you only prepared it to be executed. You need to call sqllite3_step to read the first row. The you can call sqllit3_column_int.
You can see how to call it in this tutorial: http://www.raywenderlich.com/913/sqlite-tutorial-for-ios-making-our-app

Nested bridge transfer call with ARC

I'm trying to get the email address of a contact and the type of the email address (work/home). This is the code I've written
//Assume that 'personRef' of type ABRecordRef is available
....
ABMultiValueRef emailRef = ABRecordCopyValue(personRef, kABPersonEmailProperty);
NSMutableArray *emailAddresses = nil, *emailAddressLabels = nil;
int ctr = ABMultiValueGetCount(emailRef);
if(ctr!=0) {
emailAddresses = [[NSMutableArray alloc]init];
emailAddressLabels = [[NSMutableArray alloc]init];
for(int i=0; i<ctr; i++) {
NSString *eId = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(emailRef, i);
[emailAddresses addObject:eId];
CFStringRef label = ABMultiValueCopyLabelAtIndex (emailRef, i);
if(label!=NULL) {
NSString *eType = (__bridge_transfer NSString*)ABAddressBookCopyLocalizedLabel(label);
if([eType isEqualToString:#""]) {
[emailAddressLabels addObject:#"Email"];
} else {
[emailAddressLabels addObject:eType];
}
CFRelease(label);
}
}
}
The code crashes at CFRelease(label), but to prevent memory leak, I should be doing it. When I try the following
NSString *eType = (__bridge_transfer NSString*) ABAddressBookCopyLocalizedLabel(ABMultiValueCopyLabelAtIndex (emailRef, i));
I get the following warning from ARC
1. Call to function 'ABMultiValueCopyLabelAtIndex' returns a Core Foundation object with a +1 retain count
2. Object leaked: allocated object is not referenced later in this execution path and has a retain count of +1
Now the question I have is, How to do a nesting __bridge_transfer call?
NSString *eType = (__bridge_transfer NSString*)
ABAddressBookCopyLocalizedLabel(
ABMultiValueCopyLabelAtIndex (emailRef, i) /* <-- this object is leaked */
);
This code is invalid because you leak the Label here (which I realise is your point I guess?).
You should run that code under the Instruments NSZombie instrument, it will trace all the retain/releases and you'll have a clue what's going on, because frankly, looking at the code, I don't see why it's wrong.

Append String with NSURL

I have following string , which i want to append with NSURL and after appending i want the result in NSURL
{ "deviceid":"3c27c99ac4b159aca81de8f5d266478f00000000 ","nickname":"sad","gender":0,"marital":0,"children":1,"job":"asd","message":"Asd","pushid":"3c27c99ac4b159aca81de8f5d266478f00000000"}
Can , Anybody help me please .
Thanks in advance .
You haven't stated what you expect the final URL to look like, so I have assumed you want to add the names and values from your record string as a query string to the original URL.
The following method will return a combined URL when given a base URL and string like the one you have provided above:
-(NSURL *)URLWithRecord:(NSString *)record relativeToURL:(NSURL *)originalURL
{
NSCharacterSet * unwantedDelimeters = [NSCharacterSet characterSetWithCharactersInString:#"{}"];
NSCharacterSet * fieldSeperator = [NSCharacterSet characterSetWithCharactersInString:#","];
NSCharacterSet * nameValueSeperator = [NSCharacterSet characterSetWithCharactersInString:#":"];
NSCharacterSet * quotes = [NSCharacterSet characterSetWithCharactersInString:#"\""];
record = [record stringByTrimmingCharactersInSet:unwantedDelimeters];
NSArray * fields = [record componentsSeparatedByCharactersInSet:fieldSeperator];
NSMutableString * queryString = [NSMutableString stringWithString:#"?"];
for (NSUInteger fieldCount = 0; fieldCount < [fields count]; fieldCount++) {
NSString * field = [fields objectAtIndex:fieldCount];
NSArray * nameValue = [field componentsSeparatedByCharactersInSet:nameValueSeperator];
NSString * name = [[nameValue objectAtIndex:0] stringByTrimmingCharactersInSet:quotes];
NSString * value = [[nameValue objectAtIndex:1] stringByTrimmingCharactersInSet:quotes];
if (fieldCount == ([fields count]-1) ) {
[queryString appendFormat:#"%#=%#", name, value];
} else {
[queryString appendFormat:#"%#=%#&", name, value];
}
}
NSURL * combinedURL = [NSURL URLWithString:queryString relativeToURL:originalURL];
return combinedURL;
}
When tested with the following code:
NSURL * originalURL = [NSURL URLWithString:#"http://www.example.com"];
NSString * string = #"{\"deviceid\":\"3c27c99ac4b159aca81de8f5d266478f00000000\",\"nickname\":\"sad\",\"gender\":0,\"marital\":0,\"children\":1,\"job\":\"asd\",\"message\":\"Asd\",\"pushid\":\"3c27c99ac4b159aca81de8f5d266478f00000000\"}";
NSURL * combinedURL = [self URLWithRecord:string relativeToURL:originalURL];
NSLog(#"result=\"%#\"", [combinedURL absoluteString]);
The output is:
result="http://www.example.com?deviceid=3c27c99ac4b159aca81de8f5d266478f00000000&nickname=sad&gender=0&marital=0&children=1&job=asd&message=Asd&pushid=3c27c99ac4b159aca81de8f5d266478f00000000"
The method provided assumes that there are no erroneous spaces in the record string and that the names and values in the record only contain ASCII numbers and letters. It will return a nil value if the record contains names or values that contain URL problem characters (such as a space). If you suspect that such characters will be involved, you will need to rewrite the method accordingly - replacing such characters with URL escape codes.
NSString *str=#"";
NSString *str1=#"\"deviceid\":\"3c27c99ac4b159aca81de8f5d266478f00000000 \",\"nickname\":\"sad\",\"gender\":0,\"marital\":0,\"children\":1,\"job:\"asd\",\"message\":\"Asd\",\"pushid\":\"3c27c99ac4b159aca81de8f5d266478f00000000\"";
NSURL *url=[NSURL URLWithString:#"give your url"];
NSArray *components = [url pathComponents];
for (NSString *c in components)
{
str=[str stringByAppendingString:c];
}
str=[str stringByAppendingString:str1];
NSURL *newurl=[NSURL URLWithString:#"str"];

+ (NSString *)decodeFromPercentEscapeString:(NSString *)string potential leak

I got issues when I analyse my code.
Espacially on this methods.
I pucked up this lines on the web. It works well but I got a Portential leak message
Potential leak on the object. (on the return).
// Encode a string to embed in an URL.
+ (NSString *)encodeToPercentEscapeString:(NSString*)string {
return (NSString *)
CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef) string,
NULL,
(CFStringRef) #"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
}
// Decode a percent escape encoded string.
+ (NSString *)decodeFromPercentEscapeString:(NSString *)string {
return (NSString *)
CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL,
(CFStringRef) string,
CFSTR(""),
kCFStringEncodingUTF8);
}
Thanks.
I just found this post:
iPhone memory leaking?
I have to release the CFString with CFRelease();
+ (NSString *)encodeToPercentEscapeString:(NSString*)string {
CFStringRef str = CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef) string,
NULL,
(CFStringRef) #"!*'();:#&=+$,/?%#[]",
kCFStringEncodingUTF8);
NSString *s = [NSString stringWithString:(NSString *)str];
CFRelease(str);
return s;
}

Trim spaces from end of a NSString

I need to remove spaces from the end of a string. How can I do that?
Example: if string is "Hello " it must become "Hello"
Taken from this answer here: https://stackoverflow.com/a/5691567/251012
- (NSString *)stringByTrimmingTrailingCharactersInSet:(NSCharacterSet *)characterSet {
NSRange rangeOfLastWantedCharacter = [self rangeOfCharacterFromSet:[characterSet invertedSet]
options:NSBackwardsSearch];
if (rangeOfLastWantedCharacter.location == NSNotFound) {
return #"";
}
return [self substringToIndex:rangeOfLastWantedCharacter.location+1]; // non-inclusive
}
Another solution involves creating mutable string:
//make mutable string
NSMutableString *stringToTrim = [#" i needz trim " mutableCopy];
//pass it by reference to CFStringTrimSpace
CFStringTrimWhiteSpace((__bridge CFMutableStringRef) stringToTrim);
//stringToTrim is now "i needz trim"
Here you go...
- (NSString *)removeEndSpaceFrom:(NSString *)strtoremove{
NSUInteger location = 0;
unichar charBuffer[[strtoremove length]];
[strtoremove getCharacters:charBuffer];
int i = 0;
for(i = [strtoremove length]; i >0; i--) {
NSCharacterSet* charSet = [NSCharacterSet whitespaceCharacterSet];
if(![charSet characterIsMember:charBuffer[i - 1]]) {
break;
}
}
return [strtoremove substringWithRange:NSMakeRange(location, i - location)];
}
So now just call it. Supposing you have a string that has spaces on the front and spaces on the end and you just want to remove the spaces on the end, you can call it like this:
NSString *oneTwoThree = #" TestString ";
NSString *resultString;
resultString = [self removeEndSpaceFrom:oneTwoThree];
resultString will then have no spaces at the end.
NSString *trimmedString = [string stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
//for remove whitespace and new line character
NSString *trimmedString = [string stringByTrimmingCharactersInSet:
[NSCharacterSet punctuationCharacterSet]];
//for remove characters in punctuation category
There are many other CharacterSets. Check it yourself as per your requirement.
To remove whitespace from only the beginning and end of a string in Swift:
Swift 3
string.trimmingCharacters(in: .whitespacesAndNewlines)
Previous Swift Versions
string.stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()))
Swift version
Only trims spaces at the end of the String:
private func removingSpacesAtTheEndOfAString(var str: String) -> String {
var i: Int = countElements(str) - 1, j: Int = i
while(i >= 0 && str[advance(str.startIndex, i)] == " ") {
--i
}
return str.substringWithRange(Range<String.Index>(start: str.startIndex, end: advance(str.endIndex, -(j - i))))
}
Trims spaces on both sides of the String:
var str: String = " Yolo "
var trimmedStr: String = str.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())
This will remove only the trailing characters of your choice.
func trimRight(theString: String, charSet: NSCharacterSet) -> String {
var newString = theString
while String(newString.characters.last).rangeOfCharacterFromSet(charSet) != nil {
newString = String(newString.characters.dropLast())
}
return newString
}
In Swift
To trim space & newline from both side of the String:
var url: String = "\n http://example.com/xyz.mp4 "
var trimmedUrl: String = url.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
A simple solution to only trim one end instead of both ends in Objective-C:
#implementation NSString (category)
/// trims the characters at the end
- (NSString *)stringByTrimmingSuffixCharactersInSet:(NSCharacterSet *)characterSet {
NSUInteger i = self.length;
while (i > 0 && [characterSet characterIsMember:[self characterAtIndex:i - 1]]) {
i--;
}
return [self substringToIndex:i];
}
#end
And a symmetrical utility for trimming the beginning only:
#implementation NSString (category)
/// trims the characters at the beginning
- (NSString *)stringByTrimmingPrefixCharactersInSet:(NSCharacterSet *)characterSet {
NSUInteger i = 0;
while (i < self.length && [characterSet characterIsMember:[self characterAtIndex:i]]) {
i++;
}
return [self substringFromIndex:i];
}
#end
To trim all trailing whitespace characters (I'm guessing that is actually your intent), the following is a pretty clean & concise way to do it.
Swift 5:
let trimmedString = string.replacingOccurrences(of: "\\s+$", with: "", options: .regularExpression)
Objective-C:
NSString *trimmedString = [string stringByReplacingOccurrencesOfString:#"\\s+$" withString:#"" options:NSRegularExpressionSearch range:NSMakeRange(0, string.length)];
One line, with a dash of regex.
The solution is described here: How to remove whitespace from right end of NSString?
Add the following categories to NSString:
- (NSString *)stringByTrimmingTrailingCharactersInSet:(NSCharacterSet *)characterSet {
NSRange rangeOfLastWantedCharacter = [self rangeOfCharacterFromSet:[characterSet invertedSet]
options:NSBackwardsSearch];
if (rangeOfLastWantedCharacter.location == NSNotFound) {
return #"";
}
return [self substringToIndex:rangeOfLastWantedCharacter.location+1]; // non-inclusive
}
- (NSString *)stringByTrimmingTrailingWhitespaceAndNewlineCharacters {
return [self stringByTrimmingTrailingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
And you use it as such:
[yourNSString stringByTrimmingTrailingWhitespaceAndNewlineCharacters]
I came up with this function, which basically behaves similarly to one in the answer by Alex:
-(NSString*)trimLastSpace:(NSString*)str{
int i = str.length - 1;
for (; i >= 0 && [str characterAtIndex:i] == ' '; i--);
return [str substringToIndex:i + 1];
}
whitespaceCharacterSet besides space itself includes also tab character, which in my case could not appear. So i guess a plain comparison could suffice.
let string = " Test Trimmed String "
For Removing white Space and New line use below code :-
let str_trimmed = yourString.trimmingCharacters(in: .whitespacesAndNewlines)
For Removing only Spaces from string use below code :-
let str_trimmed = yourString.trimmingCharacters(in: .whitespaces)
NSString* NSStringWithoutSpace(NSString* string)
{
return [string stringByReplacingOccurrencesOfString:#" " withString:#""];
}

Resources