Using Swift to unescape unicode characters, ie \u1234 - utf-8

I have problems with special characters when using JSON in xcode 6 with swift
I found these codes in Cocoa/objective C to solve some problems converting accent but could not make it work in Swift. Any suggestions for how to use it? ... best alternative suggestions would also be cool ...
Thanks
NSString *input = #"\\u5404\\u500b\\u90fd";
NSString *convertedString = [input mutableCopy];
CFStringRef transform = CFSTR("Any-Hex/Java");
CFStringTransform((__bridge CFMutableStringRef)convertedString, NULL, transform, YES);
NSLog(#"convertedString: %#", convertedString);
// prints: 各個都, tada!

It's fairly similar in Swift, though you still need to use the Foundation string classes:
let transform = "Any-Hex/Java"
let input = "\\u5404\\u500b\\u90fd" as NSString
var convertedString = input.mutableCopy() as NSMutableString
CFStringTransform(convertedString, nil, transform as NSString, 1)
println("convertedString: \(convertedString)")
// convertedString: 各個都
(The last parameter threw me for a loop until I realized that Boolean in Swift is a type alias for UInt - YES in Objective-C becomes 1 in Swift for these types of methods.)

Swift String extension:
extension String {
var unescapingUnicodeCharacters: String {
let mutableString = NSMutableString(string: self)
CFStringTransform(mutableString, nil, "Any-Hex/Java" as NSString, true)
return mutableString as String
}
}

Swift 3
let transform = "Any-Hex/Java"
let input = "\\u5404\\u500b\\u90fd" as NSString
var convertedString = input.mutableCopy() as! NSMutableString
CFStringTransform(convertedString, nil, transform as NSString, true)
print("convertedString: \(convertedString)")
// convertedString: 各個都

Related

Getting the iOS device token for push notifciations in RubyMotion

I need the user's device token as a hexadecimal string to send push notifications. I used to do this by using the deviceToken 'description', but this doesn't work anymore in iOS13. I found several solutions for this in Objective-C and Swift.
How can I convert my device token (NSData) into an NSString?
The problem however, is that deviceToken.bytes returns a Pointer in RubyMotion. And calling bytes[index] will give a different result compared to doing it in Objective-C. I've tried a lot of different things, but I can't seem to get it to work. The RubyMotion docs about Pointers are also really barebones, so that doesn't help. I found the following regarding the Pointers on SO:
Pointer handling with RubyMotion
It says that I have to do bytes + index instead of bytes[index]. I currently have the following code:
def application(application, didRegisterForRemoteNotificationsWithDeviceToken: device_token)
string = token_to_string(device_token)
end
def token_to_string(device_token)
data_length = device_token.length
if data_length == 0
nil
else
data_buffer = device_token.bytes
token = NSMutableString.stringWithCapacity(data_length * 2)
index = 0
begin
buffer = data_buffer + index
token.appendFormat('%02.2hhx', buffer)
index += 1
end while index < data_length
token.copy
end
end
It's not giving any errors, but the generated device token doesn't seem to be correct. Any advice would be greatly appreciated!
I've been trying to think of a pure RubyMotion solution, but I just don't understand 'Pointers' enough to get it to work. So I've gone a different way: extending the NSData class.
1) Create the folder vendor/NSData+Hex inside your project.
2) Create the file NSData+Hex.h inside the folder and put this inside:
#import <Foundation/Foundation.h>
#interface NSData (Hex)
#property (nonatomic, copy, readonly) NSString *hexString;
#end
3) Now create NSData+Hex.m in the same folder and put this in the file:
#import "NSData+Hex.h"
#implementation NSData (Hex)
- (NSString *) hexString
{
NSUInteger len = self.length;
if (len == 0) {
return nil;
}
const unsigned char *buffer = self.bytes;
NSMutableString *hexString = [NSMutableString stringWithCapacity:(len * 2)];
for (int i = 0; i < len; ++i) {
[hexString appendFormat:#"%02x", buffer[i]];
}
return [hexString copy];
}
#end
4) Add this to your Rakefile:
app.vendor_project('vendor/NSData+Hex', :static)
5) Now you can simply call deviceToken.hexString within def application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken).
If anyone can think of a pure RubyMotion solution, feel free to answer. For now, it's at least working. :)
Hi I use the following to convert NSData to an NSString that can then be manipulated in ruby.
class NSData
def to_s
NSString.alloc.initWithBytes(bytes, length: length, encoding: NSUTF8StringEncoding)
end
end
I do the following:
token = deviceToken.description.gsub(/[<> ]/, '')

How can I find the substrings from the NSTextCheckingResult objects in swift?

I wonder how it is possible to find substrings from a NSTextCheckingResult object. I have tried this so far:
import Foundation {
let input = "My name Swift is Taylor Swift "
let regex = try NSRegularExpression(pattern: "Swift|Taylor", options:NSRegularExpressionOptions.CaseInsensitive)
let matches = regex.matchesInString(input, options: [], range: NSMakeRange(0, input.characters.count))
for match in matches {
// what will be the code here?
}
Try this:
import Foundation
let input = "My name Swift is Taylor Swift "// the input string where we will find for the pattern
let nsString = input as NSString
let regex = try NSRegularExpression(pattern: "Swift|Taylor", options: NSRegularExpressionOptions.CaseInsensitive)
//matches will store the all range objects in form of NSTextCheckingResult
let matches = regex.matchesInString(input, options: [], range: NSMakeRange(0, input.characters.count)) as Array<NSTextCheckingResult>
for match in matches {
// what will be the code
let range = match.range
let matchString = nsString.substringWithRange(match.range) as String
print("match is \(range) \(matchString)")
}
Here is code that works for Swift 3. It returns array of String
results.map {
String(text[Range($0.range, in: text)!])
}
So overall example could be like this:
let regex = try NSRegularExpression(pattern: regex)
let results = regex.matches(in: text,
range: NSRange(text.startIndex..., in: text))
return results.map {
String(text[Range($0.range, in: text)!])
}
You can put this code inside the for loop. The str will contain the string that matches.
let range = match.range
let str = (input as NSString).substringWithRange(range)

Convert NSRange contents to NSString?

I am working on a Cocoa Mac OSX app, and I am wondering if it is possible to present the contents of an NSRange found by:
NSRange range;
range.location = 4;
range.length = 4;
as an NSString?
e.g. in the example above, if I had a string with contents "abcdefgh", presenting the contents of the above range as a string would give "efgh". Is this possible?
Code:
NSString *string = #"abcdefgh";
NSRange range;
range.location = 4;
range.length = 4;
NSString *subString = [string substringWithRange:range];
NSLog(#"%#",subString);
Output:
efgh
Try the method substringWithRange from NSString.
NSString* original = #"abcdefgh";
NSLog(#"Substring: %#", [original substringWithRange:range]);

Check if NSString instance is contained in an NSArray

I have an array with a bunch of strings and I want to check if a certain string is contained in the array. If I use the containsObject: message on the array, I'm getting correct results. Do all NSString objects with the same string point to the same object? Or why is the containsObject: working?
NSArray *stringArray = [NSArray arrayWithObjects:#"1",#"2",#"3",anotherStringValue, nil];
if([stringArray containsObject:#"2"]){
//DO SOMETHING
}
Yes, hard-coded NSStrings (string literals) (that is any #"..." in your source code) are turned into strings that exist indefinitely while your process is running.
However NSArray's containsObject: methods calls isEqual: on its objects, hence even a dynamically created string such as [NSString stringWithFormat:#"%d", 2] would return YES in your sample snippet.
This is because NSString's isEqual: (or more precisely its isEqualToString:) method is implemented to be content aware (vs. comparing pointer identities) and thus returns YES for any pair of strings containing the very same sequence of characters (at time of comparison), no matter how and when they were created.
To check for equal (pointer-)identity you'd have to enumerate your array and compare via
NSString *yourString = #"foo";
BOOL identicalStringFound = NO;
for (NSString *someString in stringArray) {
if (someString == yourString) {
identicalStringFound = YES;
break;
}
}
(which you most likely wouldn't want, though).
Or in a more convenient fashion:
BOOL identicalStringFound = [stringArray indexOfObjectIdenticalTo:someString] != NSNotFound;
(you most likely wouldn't want this one either).
Summing up:
So the reason you're getting a positive reply from containsObject: is NOT because literal strings share the same constant instance, BUT because containsObject: by convention calls isEqual:, which is content aware.
You might want to read the (short) documentation for isEqual: from the NSObject protocol.
containsObject: performs a value check, not a pointer check. It uses the isEqual: method defined by NSObject and overridden by other objects for testing. Therefore, if two strings contain the same sequence of characters, they will be considered the same.
The distinction between pointer testing and value testing is very important in some cases. Constant strings defined in source code are combined by the compiler so that they are the same object. However, strings created dynamically are not the same object. Here is an example program which will demonstrate this:
int main(int argc, char **argv) {
NSAutoreleasePool *p = [NSAutoreleasePool new];
NSString *constantString = #"1";
NSString *constantString2 = #"1";
NSString *dynamicString = [NSString stringWithFormat:#"%i",1];
NSArray *theArray = [NSArray arrayWithObject:constantString];
if(constantString == constantString2) NSLog(#"constantString == constantString2");
else NSLog(#"constantString != constantString2");
if(constantString == dynamicString) NSLog(#"constantString == dynamicString");
else NSLog(#"constantString != dynamicString");
if([constantString isEqual:dynamicString]) NSLog(#"[constantString isEqual:dynamicString] == YES");
else NSLog(#"[constantString isEqual:dynamicString] == NO");
NSLog(#"theArray contains:\n\tconstantString: %i\n\tconstantString2: %i\n\tdynamicString: %i",
[theArray containsObject:constantString],
[theArray containsObject:constantString2],
[theArray containsObject:dynamicString]);
}
The output of this program is:
2011-04-27 17:10:54.686 a.out[41699:903] constantString == constantString2
2011-04-27 17:10:54.705 a.out[41699:903] constantString != dynamicString
2011-04-27 17:10:54.706 a.out[41699:903] [constantString isEqual:dynamicString] == YES
2011-04-27 17:10:54.706 a.out[41699:903] theArray contains:
constantString: 1
constantString2: 1
dynamicString: 1
You can use containsObject to findout if certain string is exist,
NSArray *stringArray = [NSArray arrayWithObjects:#"1",#"2",#"3",anotherStringValue, nil];
if ( [stringArray containsObject: stringToFind] ) {
// if found
} else {
// if not found
}

calling a C function using cocoa

I have a C function with the following method signature.
NSString* md5( NSString *str )
How do I call this function, pass in a string, and save the returned string?
I tried the following, but it did not work:
NSString *temp= [[NSString alloc]initWithString:md5(password)];
thanks for your help
You're making it too hard. The stuff in []'s is effectively smalltalk. What you want is to just call the function in C:
NSString * temp = md5(password);
What is password? Is password a common "char *" pointer? Is the md5 signature you put correct?
If that's the case, you could:
NSString *temp = [[NSString alloc] initWithCString:password encoding:NSASCIIStringEncoding];
If your md5 signature is: char *md5(char *password), and you have you password stored in a NSString, you could:
NSString password = #"mypass";
char buff[128];
NSString *temp = [[NSString alloc] initWithString:password];
[temp getCString:buff maxLength:128 encoding:NSASCIIStringEncoding];
char *md5 = md5(buff);
// then you could do whatever you want with md5 var

Resources