I have a simple ROT13 method that encodes or decodes a string.
+ (NSString *)ROT13encodeString:(NSString *)aString {
if (!aString) {
return nil;
}
// Find text between brackets
NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:#"[]"];
NSArray *splitString = [aString componentsSeparatedByCharactersInSet:delimiters];
// ???
NSString *newString;
unsigned length;
unichar *buf;
unsigned i;
length = [aString length];
buf = malloc( (length + 1) * sizeof(unichar) );
[aString getCharacters:buf];
buf[length] = (unichar)0; // not really needed....
for (i = 0; i < length; i++) {
if (buf[i] >= (unichar)'a' && buf[i] <= (unichar) 'z') {
buf[i] += 13;
if (buf[i] > 'z') buf[i] -= 26;
} else if (buf[i] >= (unichar)'A' && buf[i] <= (unichar) 'Z') {
buf[i] += 13;
if (buf[i] > 'Z') buf[i] -= 26;
}
}
newString = [NSString stringWithCharacters:buf length:length];
free(buf);
return newString;
}
However, within the text to encode, there are "safe" words that are placed within brackets []. The words, including the brackets should never be encoded, they always need to be in their non-encoded state.
I figured I could pull out all occururances of the bracketed text, but not sure how it would help:
NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:#"[]"];
NSArray *splitString = [aString componentsSeparatedByCharactersInSet:delimiters];
How could I modify my current method to include this?
I don't code in objective-c, but I think this should be close:
+ (NSString *)ROT13encodeString:(NSString *)aString {
if (!aString) {
return nil;
}
// Find text between brackets
NSCharacterSet *delimiters = [NSCharacterSet characterSetWithCharactersInString:#"[]"];
NSArray *splitString = [aString componentsSeparatedByCharactersInSet:delimiters];
// ???
NSString *newString;
unsigned length;
unichar *buf;
unsigned i;
unsigned level;
length = [aString length];
buf = malloc( (length + 1) * sizeof(unichar) );
[aString getCharacters:buf];
buf[length] = (unichar)0; // not really needed....
level = 0;
for (i = 0; i < length; i++) {
if (buf[i] == (unichar)'[') {
level++;
} else if (buf[i] == (unichar)']') {
level--;
} else if (level==0 && buf[i] >= (unichar)'a' && buf[i] <= (unichar) 'z') {
buf[i] += 13;
if (buf[i] > 'z') buf[i] -= 26;
} else if (level==0 && buf[i] >= (unichar)'A' && buf[i] <= (unichar) 'Z') {
buf[i] += 13;
if (buf[i] > 'Z') buf[i] -= 26;
}
}
newString = [NSString stringWithCharacters:buf length:length];
free(buf);
return newString;
}
Related
Let say number = 0 and otherNumber = 10. The loop will execute. But what if number = 10 and otherNumber = 0. I want the compiler to pick the smallest number and use it to proceed.
The code I have so far is here:
- (NSString *) stringWithNumbersBetweenNumber:(NSInteger)number andOtherNumber: (NSInteger)otherNumber {
if (number <= otherNumber) {
NSMutableString *indices = [NSMutableString stringWithCapacity:1];
for (NSInteger i= number; i <= otherNumber; i++) {
[indices appendFormat:#"%d", i];
}
} else {
NSMutableString *indices = [NSMutableString stringWithCapacity:1];
for (NSInteger i= otherNumber; i <= number; i++) {
[indices appendFormat:#"%d", i];
}
}
return #"%#", indices;
}
A simple fix is to move the declaration of indices outside the conditional:
- (NSString *) stringWithNumbersBetweenNumber:(NSInteger)number andOtherNumber: (NSInteger)otherNumber {
NSMutableString *indices = [NSMutableString stringWithCapacity:1];
if (number <= otherNumber) {
for (NSInteger i= number; i <= otherNumber; i++) {
[indices appendFormat:#"%d", i];
}
} else {
for (NSInteger i= otherNumber; i <= number; i++) {
[indices appendFormat:#"%d", i];
}
}
return indices;
}
You could further unify your like this:
- (NSString *) stringWithNumbersBetweenNumber:(NSInteger)number andOtherNumber: (NSInteger)otherNumber {
NSInteger from, to;
if (number <= otherNumber) {
from = number;
to = otherNumber;
} else {
from = otherNumber;
to = number;
}
NSMutableString *indices = [NSMutableString stringWithCapacity:1];
for (NSInteger i= from; i <= tp; i++) {
[indices appendFormat:#"%d", i];
}
return indices;
}
One option would be:
- (NSString *) stringWithNumbersBetweenNumber:(NSInteger)number andOtherNumber: (NSInteger)otherNumber {
NSInteger minNum = MIN(number, otherNumber);
NSInteger maxNum = MAX(number, otherNumber);
NSMutableString *indices = [NSMutableString stringWithCapacity:maxNum - minNum + 1];
for (NSInteger i = minNum; i <= maxNum; i++) {
[indices appendFormat:#"%d", i];
}
return indices; // or [indices copy];
}
Pick one of the variables to always be considered the larger variable, and then do a simple swap-test before the function body proper.
- (NSString *) stringWithNumbersBetweenNumber:(NSInteger)number andOtherNumber: (NSInteger)otherNumber {
if (number < otherNumber) {
NSInteger temp = number;
number = otherNumber;
otherNumber = temp;
}
NSMutableString *indices = [NSMutableString stringWithCapacity:1];
for (NSInteger i= otherNumber; i <= number; i++) {
[indices appendFormat:#"%d", i];
}
return #"%#", indices;
}
(Apologies for any code errors, Objective-C isn't my primary language)
I'm trying to sort my arrays with a particular sequence using an NSComparisonResult. I'm unable to figure out how to achieve the sequence I'm wanting.
I'm trying to weight Emojis towards the top (sequence of Emojis doesn't matter), followed by A-Z letters with giving a weight towards lowercase before uppercase, followed by numbers, followed by punctuation, then by symbols, and whatever else after that I dont care about at this point. I've gotten pretty close so far, but am still coming up short with what I want.
The sequence I'm trying to achieve would look like this as the output:
("\Ud83d\Ude03",
a,
A,
aa,
aA,
ab,
aB,
a1,
A1,
1,
01,
11,
001,
0001,
1001,
"#",
"#a",
"#1",
"$12",
"$0012")
Based upon this array as the input:
#[ #"a", #"aA", #"aa", #"A", #"aB", #"11", #"1001", #"ab", #"001", #"01",
#"a1", #"A1", #"😃", #"0001", #"1", #"#", #"$12", #"$0012", #"#a", #"#1" ];
But this is the output I'm getting:
("\Ud83d\Ude03",
a,
A,
aA,
aa,
aB,
ab,
a1,
A1,
0001,
001,
01,
1,
1001,
11,
"#a",
"#1",
"$0012",
"$12",
"#")
Code:
- (NSArray *)sortedArray:(NSArray *)input
{
NSArray *newArray = [input sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2)
{
NSString *nameOne = obj1;
NSString *nameTwo = obj2;
NSString *startOne;
NSString *startTwo;
NSInteger currentIndex = 0;
NSInteger maxIndex = (nameOne.length < nameTwo.length) ? nameOne.length : nameTwo.length;
NSCharacterSet *decimalDigitCharSet = [NSCharacterSet decimalDigitCharacterSet];
NSCharacterSet *punctuationCharSet = [NSCharacterSet punctuationCharacterSet];
NSCharacterSet *symbolCharSet = [NSCharacterSet symbolCharacterSet];
NSMutableCharacterSet *nonPriorityCharSet = [[NSMutableCharacterSet alloc]init];
[nonPriorityCharSet formUnionWithCharacterSet:punctuationCharSet];
[nonPriorityCharSet formUnionWithCharacterSet:symbolCharSet];
do
{
if (currentIndex < maxIndex)
{
startOne = [nameOne substringWithRange:NSMakeRange(currentIndex, 1)];
startTwo = [nameTwo substringWithRange:NSMakeRange(currentIndex, 1)];
currentIndex++;
}
else
{
if (nameOne.length == nameTwo.length)
{
return NSOrderedSame;
}
else
{
return (nameOne.length < nameTwo.length) ? NSOrderedAscending : NSOrderedDescending;
}
}
}
while ([startOne isEqualToString:startTwo]);
{
NSRange rangeOne = [startOne rangeOfCharacterFromSet:nonPriorityCharSet];
NSRange rangeTwo = [startTwo rangeOfCharacterFromSet:nonPriorityCharSet];
if (rangeOne.length > 0 || rangeTwo.length > 0)
{
return (rangeOne.length > 0) ? NSOrderedDescending : NSOrderedAscending;
}
NSRange decimalRangeOne = [startOne rangeOfCharacterFromSet:decimalDigitCharSet];
NSRange decimalRangeTwo = [startTwo rangeOfCharacterFromSet:decimalDigitCharSet];
if (decimalRangeOne.length > 0 || decimalRangeTwo.length > 0)
{
if (decimalRangeOne.length == decimalRangeTwo.length)
{
return (startOne.intValue > startTwo.intValue) ? NSOrderedDescending : NSOrderedAscending;
}
else if (decimalRangeOne.length > decimalRangeTwo.length)
{
return NSOrderedDescending;
}
else if (decimalRangeTwo.length > decimalRangeOne.length)
{
return NSOrderedAscending;
}
}
}
return [nameOne localizedCaseInsensitiveCompare:nameTwo];
}];
return newArray;
}
You started well. But you didn't properly check for all the rules that you have set. I have created some categories based on you rules, and sort using them.
- (NSArray *)sortedArray:(NSArray *)input
{
__block id blocksafeSelf = self;
NSArray *newArray = [input sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
NSString *nameOne = obj1;
NSString *nameTwo = obj2;
NSInteger currentIndex = 0;
unichar charOne = [nameOne characterAtIndex:0];
unichar charTwo = [nameTwo characterAtIndex:0];
short maxLength = MIN(nameOne.length, nameTwo.length);
do {
charOne = [nameOne characterAtIndex:currentIndex];
charTwo = [nameTwo characterAtIndex:currentIndex];
currentIndex ++;
}
while (charOne == charTwo && currentIndex < maxLength);
short oneCategory = [blocksafeSelf getCharCategory:charOne];
short twoCategory = [blocksafeSelf getCharCategory:charTwo];
if (oneCategory != twoCategory) {
return oneCategory > twoCategory;
}
else if (oneCategory != 1) {
if (nameOne.length != nameTwo.length) {
return nameOne.length > nameTwo.length;
}
else {
return charOne > charTwo;
}
}
else {
if (nameOne.length != nameTwo.length) {
return nameOne.length > nameTwo.length;
}
else {
oneCategory = [blocksafeSelf getLetterCategory:charOne];
twoCategory = [blocksafeSelf getLetterCategory:charTwo];
if (oneCategory == twoCategory) {
return charOne > charTwo;
}
else {
unichar tempCharOne = oneCategory == 7 ? charOne + 32 : charOne;
unichar tempCharTwo = twoCategory == 7 ? charTwo + 32 : charTwo;
if (tempCharOne != tempCharTwo) {
return tempCharOne > tempCharTwo;
}
else {
return oneCategory > twoCategory;
}
}
}
}
return [nameOne localizedCaseInsensitiveCompare:nameTwo];
}];
return newArray;
}
- (short)getCharCategory:(unichar)character {
if (character > 255) { // emoji
return 0;
}
NSCharacterSet *letterCaseCharSet = [NSCharacterSet letterCharacterSet];
if ([letterCaseCharSet characterIsMember:character]) return 1;
NSCharacterSet *decimalDigitCharSet = [NSCharacterSet decimalDigitCharacterSet];
if ([decimalDigitCharSet characterIsMember:character]) return 2;
NSCharacterSet *punctuationCharSet = [NSCharacterSet punctuationCharacterSet];
if ([punctuationCharSet characterIsMember:character]) return 3;
NSCharacterSet *symbolCharSet = [NSCharacterSet symbolCharacterSet];
if ([symbolCharSet characterIsMember:character]) return 4;
return 5;
}
- (short)getLetterCategory:(unichar)character {
NSCharacterSet *lowerCaseCharSet = [NSCharacterSet lowercaseLetterCharacterSet];
if ([lowerCaseCharSet characterIsMember:character]) return 6;
return 7;
}
I have a jpg image which I am converting to data using the UIImageJPEGRepresentation function
I am then sending the data to a server online and getting it back when it is needed though I get this string:
<ffd8ffe0 00104a46 49460001 01000001 00010000 ffe10058 45786966 00004d4d...>
And I don't know how to convert it back to an image
Thanks in advance
I managed to find a way to do it by converting the string to a base64 string like this:
+ (NSString *) encodeToBase64:(NSData *) rawBytes {
return [StringMethods encodeToBase64:(const uint8_t*) rawBytes.bytes length:rawBytes.length];
}
+ (NSString *) encodeToBase64:(const uint8_t *)input length:(NSInteger) length {
NSMutableData *data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t *output = (uint8_t *)data.mutableBytes;
for (NSInteger i = 0; i < length; i += 3) {
NSInteger value = 0;
for (NSInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger index = (i / 3) * 4;
output[index + 0] = encodingTable[(value >> 18) & 0x3F];
output[index + 1] = encodingTable[(value >> 12) & 0x3F];
output[index + 2] = (i + 1) < length ? encodingTable[(value >> 6) & 0x3F] : '=';
output[index + 3] = (i + 2) < length ? encodingTable[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}
Then I saved it onto the server then when loading back in I used this function:
- (NSData *)base64DataFromString: (NSString *)string {
unsigned long ixtext, lentext;
unsigned char ch, inbuf[4], outbuf[3];
short i, ixinbuf;
Boolean flignore, flendtext = false;
const unsigned char *tempcstring;
NSMutableData *theData;
if (string == nil){
return [NSData data];
}
ixtext = 0;
tempcstring = (const unsigned char *)[string UTF8String];
lentext = [string length];
theData = [NSMutableData dataWithCapacity: lentext];
ixinbuf = 0;
while (true) {
if (ixtext >= lentext) {
break;
}
ch = tempcstring [ixtext++];
flignore = false;
if ((ch >= 'A') && (ch <= 'Z')) {
ch = ch - 'A';
} else if ((ch >= 'a') && (ch <= 'z')) {
ch = ch - 'a' + 26;
} else if ((ch >= '0') && (ch <= '9')) {
ch = ch - '0' + 52;
} else if (ch == '+') {
ch = 62;
} else if (ch == '=') {
flendtext = true;
} else if (ch == '/') {
ch = 63;
} else {
flignore = true;
}
if (!flignore) {
short ctcharsinbuf = 3;
Boolean flbreak = false;
if (flendtext) {
if (ixinbuf == 0) {
break;
}
if ((ixinbuf == 1) || (ixinbuf == 2)) {
ctcharsinbuf = 1;
} else {
ctcharsinbuf = 2;
}
ixinbuf = 3;
flbreak = true;
}
inbuf [ixinbuf++] = ch;
if (ixinbuf == 4) {
ixinbuf = 0;
outbuf[0] = (inbuf[0] << 2) | ((inbuf[1] & 0x30) >> 4);
outbuf[1] = ((inbuf[1] & 0x0F) << 4) | ((inbuf[2] & 0x3C) >> 2);
outbuf[2] = ((inbuf[2] & 0x03) << 6) | (inbuf[3] & 0x3F);
for (i = 0; i < ctcharsinbuf; i++) {
[theData appendBytes: &outbuf[i] length: 1];
}
}
if (flbreak) {
break;
}
}
}
return theData;
}
And finally to convert it into an image I was this simple method:
UIImage *image = [UIImage imageWithData:imageData];
Is what you are showing a string, or is that what you get when you display NSData? I believe that if you log binary data, it comes out as you've shown.
What you have shown is hexadecimal data, not base64, as the other poster suggested.
You could either write code that uses sscanf() to pull out int values from your hex string, or create an NSScanner object and use it's scanHexInt method. If you google "convert hex NSString to integer" you should find both approaches.
Since your values have spaces between them, NSScanner might be your best bet.
Issue
You are sending NSData to server not NSString, and that's why you are getting this NSData on that format read by you as NSString.
Solution
First you need to send it correctly as NSString to server by doing this:
NSData *imageData= UIImagePNGRepresentation(yourImage);
NSString *encodedString = [imageData base64EncodedStringWithOptions:0];
After you send it to NSString, now you get it back an manipulate it like this. I am using NSData Base64 library to perform this task.
You just manually copy these files to your project. Import the classes to your project and these lines to your code:
#import "NSData+Base64.h"
//This function converts your base64string (NSString Class) to NSData
NSData *data = [[NSData alloc] initWithData:[NSData dataFromBase64String:base64String]];
//Here is where you convert it to UIImage
UIImage *image = [UIImage imageWithData:data];
P.S You can also follow your answer, which to me seems correct, but I just wanted to let you know where were you doing wrong.
This seems to be a good answer for converting:
NSData *dataImage = [[NSData alloc] init];
dataImage = UIImagePNGRepresentation(image);
NSString *stringImage = [dataImage base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
which you can find here:NSString to UIImage
I want to create creepify text in my app with js code (creepify())
https://github.com/combatwombat/Lunicode.js/blob/master/lunicode.js
website using this js code: http://lunicode.com/creepify
My problem is when i try to combine characters, the result is'nt like in website.
I try to create 3 NSMutableArray
NSMutableArray *diacriticsTop;
NSMutableArray *diacriticsMiddle;
NSMutableArray *diacriticsBottom;
and store value like this
for (int i = 768; i <= 789; i++) {
[diacriticsTop addObject:[NSNumber numberWithInt:i]];
}
for (int i = 790; i <= 819; i++) {
if (i != 794 && i != 795) {
[diacriticsBottom addObject:[NSNumber numberWithInt:i]];
}
}
...
then i convert creepify() in js code to
- (NSString *)creepifyString:(NSString *)inputString
{
BOOL isTop = YES;
BOOL isMiddle = YES;
BOOL isBottom = YES;
NSInteger maxHeight = 15;
NSInteger randomization = 100;
NSMutableString *outputString = [[NSMutableString alloc] init];
unichar output = 0;
for (int i = 0; i < inputString.length; i++) {
unichar c = [inputString characterAtIndex:i];
if (isMiddle) {
NSNumber *temp = diacriticsMiddle[lroundf(drand48()*diacriticsMiddle.count)];
c = c + (unichar) temp;
}
// Top
if (isTop) {
// Put up to this.options.maxHeight random diacritics on top.
// optionally fluctuate the number via the randomization value (0-100%)
// randomization 100%: 0 to maxHeight
// 30%: 70% of maxHeight to maxHeight
// x%: 100-x% of maxHeight to maxHeight
int diacriticsTopLength = diacriticsTop.count - 1;
for (int count = 0,
len = maxHeight - drand48()*((randomization/100)*maxHeight); count < len; count++) {
NSNumber *temp = diacriticsTop[lroundf(drand48()*diacriticsTopLength)];
c = c + (unichar) temp;
}
}
// Bottom
if (isBottom) {
int diacriticsBottomLength = diacriticsBottom.count - 1;
for (int count = 0,
len = maxHeight - drand48()*((randomization/100)*maxHeight); count < len; count++) {
NSNumber *temp =diacriticsBottom[lroundf(drand48()*diacriticsBottomLength)];
c = c + (unichar) temp;
}
}
output = output + c;
}
[outputString appendFormat:#"%C", output];
NSLog(#"%#", outputString);
return outputString;
}
I need to find the sequence of bytes in my image data. I have next code on java, but I need make the same in obj-c.
Java:
private static int searchInBuffer(byte[] pBuf, int iBufferLen) {
for(int i = 0; i<iBufferLen - 7; i++) {
if (pBuf[i] == 'l' && pBuf[i + 1] == 'i' && pBuf[i + 2] == 'n' && pBuf[i + 3] == 'k')
return (int)pBuf[i + 4];
}
return -1;
}
public static int checkFlagInJpeg(String pFullFileName) {
int iRes = -1;
try {
File f = new File(pFullFileName);
FileInputStream is = new FileInputStream(f);
int iBufferSize = 6 * 1024, iCount = 15;
byte buf[] = new byte[iBufferSize];
while((is.available() > 0) && (iCount >= 0)) {
int iRead = is.read(buf),
iFlag = searchInBuffer(buf, iRead);
if (iFlag > 0) {
iRes = iFlag;
break;
}
iCount--;
}
is.close();
}
}
Obj-C (my version):
UIImage *image = [UIImage imageWithCGImage:[[[self.assets objectAtIndex:indexPath.row] defaultRepresentation] fullScreenImage]];
NSData *imageData = UIImageJPEGRepresentation(image, 1.0f);
NSUInteger length = MIN(6*1024, [imageData length]);
Byte *buffer = (Byte *)malloc(length);
memcpy(buffer, [imageData bytes], length);
for (int i=0; i < length - 1; i++) {
if (buffer[i] == 'l' && buffer[i + 1] == 'i' && buffer[i + 2] == 'n' && buffer[i + 3] == 'k')
NSLog(#"%c", buffer[i + 4]);
}
free(buffer);
I'm still not sure, that I understand all aspects of work with bytes, so I need a help.
UPDATE:
The problem was in getting image data. With help of Martin R. I combine to solutions in one and get next working code:
ALAssetRepresentation *repr = [[self.assets objectAtIndex:indexPath.row] defaultRepresentation];
NSUInteger size = (NSUInteger) repr.size;
NSMutableData *data = [NSMutableData dataWithLength:size];
NSError *error;
[repr getBytes:data.mutableBytes fromOffset:0 length:size error:&error];
NSData *pattern = [#"link" dataUsingEncoding:NSUTF8StringEncoding];
NSRange range = [data rangeOfData:pattern options:0 range:NSMakeRange(0, data.length)];
int iRes = -1;
if (range.location != NSNotFound) {
uint8_t flag;
[data getBytes:&flag range:NSMakeRange(range.location + range.length, 1)];
iRes = flag;
}
NSLog(#"%i", iRes);
It's working perfect! Thank you again!
NSData has a method rangeOfData:... which you can use to find the pattern:
NSData *pattern = [#"link" dataUsingEncoding:NSUTF8StringEncoding];
NSRange range = [imageData rangeOfData:pattern options:0 range:NSMakeRange(0, imageData.length)];
If the pattern was found, get the next byte:
int iRes = -1;
if (range.location != NSNotFound && range.location + range.length < imageData.length) {
uint8_t flag;
[imageData getBytes:&flag range:NSMakeRange(range.location + range.length, 1)];
iRes = flag;
}