What does NSMakeRange(i, 1) mean? - ios

I just start to learn iOS.
What does "NSMakeRange(i, 1)" mean?
for (int i = 0; i < [name length]; i++)
{
NSRange range = NSMakeRange(i, 1);
NSString *subString = [name substringWithRange:range];
const char *cString = [subString UTF8String];
if (strlen(cString) != 3)
{
return NO;
}
}
Where is it used?

NSMakeRange(i, 1) creates a range with location i and length 1. See the documentation for NSMakeRange and NSString substringWithRange for further information and related functions.

Alt-click the function name in Xcode, you’ll get a reference. The function creates a range that starts at i and has length of 1. In essence, you’re picking individual characters from the string.

Related

How to convert a NSString to NSInteger with the sum of ASCII values?

In my Objective-C code I'd like to take a NSString value, iterate through the letters, sum ASCII values of the letters and return that to the user (preferably as the NSString too).
I have already written a loop, but I don't know how to get the ASCII value of an individual character. What am I missing?
- (NSString*) getAsciiSum: (NSString*) input {
NSInteger sum = 0;
for (NSInteger index=0; index<input.length; index++) {
sum = sum + (NSInteger)[input characterAtIndex:index];
}
return [NSString stringWithFormat: #"%#", sum];
}
Note: I've seen similar questions related to obtaining ASCII values, but all of them ended up displaying the value as a string. I still don't know how to get ASCII value as NSInteger.
Here is the answer:
- (NSString *) getAsciiSum: (NSString *) input
{
NSString *input = #"hi";
int sum = 0;
for (NSInteger index = 0; index < input.length; index++)
{
char c = [input characterAtIndex:index];
sum = sum + c;
}
return [NSString stringWithFormat: #"%d", sum]);
}
This is working for me.
Hope this helps!
This should work.
- (NSInteger)getAsciiSum:(NSString *)stringToSum {
int asciiSum = 0;
for (int i = 0; i < stringToSum.length; i++) {
NSString *character = [stringToSum substringWithRange:NSMakeRange(i, 1)];
int asciiValue = [character characterAtIndex:0];
asciiSum = asciiSum + asciiValue;
}
return asciiSum;
}
Thank you to How to convert a NSString to NSInteger with the sum of ASCII values? for the reference.

How to shorten an NSString that might include e.g. Emojis to the maximal length allowed for a HFS+ filename

Apples documentation says:
[...] current file systems such as HFS+ (used by Mac OS X) allow you to create filenames with a 255-character limit [...] symbols may actually take up to the equivalent of nine English characters to store [...] This should be considered when attempting to create longer names.
How do I limit the length of a NSString in a way that it is truly shorter than 255 characters, even when it includes symbols that might take more than one character to store?
I add my current implementation below. If i add e.g. emojis to the string, while length answers the resulting string would be by far smaller than 255, it is still too long to be accepted by a NSSavePanel as file name.
NSRange stringRange = {0, MIN([fileName length], 255)};
stringRange = [fileName rangeOfComposedCharacterSequencesForRange:stringRange];
fileName = [fileName substringWithRange:stringRange];
As suggested by #JoshCaswell, I did modify this answer to a similar question. It apparently does work (I wrote several tests), but it seems strange to me. Such an obvious task cannot be so complicated to achieve?
// filename contains the NSString that should be shortened
NSMutableString *truncatedString = [NSMutableString string];
NSUInteger bytesRead = 0;
NSUInteger charIdx = 0;
while (bytesRead < 250 && charIdx < [fileName length])
{
NSRange range = [fileName rangeOfComposedCharacterSequencesForRange:NSMakeRange(charIdx, 1)];
NSString *character = [fileName substringWithRange:NSMakeRange(charIdx, range.length)];
bytesRead += [character lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
charIdx = charIdx + range.length;
if (bytesRead <= 250)
[truncatedString appendString:character];
}
rangeOfComposedCharacterSequencesForRange: is basically doing the opposite of what you want: you give it a range that counts 255 composed characters, and it gives you the byte range that encompasses those, which might end up being much more than you want.
Unfortunately to do the reverse, you have to count the bytes manually. This isn't too hard, however, with enumerateSubstringsInRange:options:usingBlock:. Passing NSStringEnumerationByComposedCharacterSequences for the options gives you exactly what it says: each composed character in turn. You can then count the size of each with lengthOfBytesUsingEncoding:, passing the final encoding you'll be using (presumably UTF-8). Add up the bytes, keeping track of the character-based index, and stop when you've seen too many.
NSString * s = /* String containing multibyte characters */;
NSUInteger maxBytes = ...;
__block NSUInteger seenBytes = 0;
__block NSUInteger truncLength = 0;
NSRange fullLength = (NSRange){0, [s length]};
[s enumerateSubstringsInRange:fullLength
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:
^(NSString *substring, NSRange substringRange,
NSRange _, BOOL *stop)
{
seenBytes += [substring lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
if( seenBytes > maxBytes ){
*stop = YES;
return;
}
else {
truncLength += substringRange.length;
}
}];
NSString * truncS = [s substringToIndex:truncLength];

Find substring range of NSString with unicode characters

If I have a string like this.
NSString *string = #"πŸ˜€1πŸ˜€3πŸ˜€5πŸ˜€7πŸ˜€"
To get a substring like #"3πŸ˜€5" you have to account for the fact the smiley face character take two bytes.
NSString *substring = [string substringWithRange:NSMakeRange(5, 4)];
Is there a way to get the same substring by using the actual character index so NSMakeRange(3, 3) in this case?
Thanks to #Joe's link I was able to create a solution that works.
This still seems like a lot of work for just trying to create a substring at unicode character ranges for an NSString. Please post if you have a simpler solution.
#implementation NSString (UTF)
- (NSString *)substringWithRangeOfComposedCharacterSequences:(NSRange)range
{
NSUInteger codeUnit = 0;
NSRange result;
NSUInteger start = range.location;
NSUInteger i = 0;
while(i <= start)
{
result = [self rangeOfComposedCharacterSequenceAtIndex:codeUnit];
codeUnit += result.length;
i++;
}
NSRange substringRange;
substringRange.location = result.location;
NSUInteger end = range.location + range.length;
while(i <= end)
{
result = [self rangeOfComposedCharacterSequenceAtIndex:codeUnit];
codeUnit += result.length;
i++;
}
substringRange.length = result.location - substringRange.location;
return [self substringWithRange:substringRange];
}
#end
Example:
NSString *string = #"πŸ˜€1πŸ˜€3πŸ˜€5πŸ˜€7πŸ˜€";
NSString *result = [string substringWithRangeOfComposedCharacterSequences:NSMakeRange(3, 3)];
NSLog(#"%#", result); // 3πŸ˜€5
Make a swift extension of NSString and use new swift String struct. Has a beautifull String.Index that uses glyphs for counting characters and range selecting. Very usefull is cases like yours with emojis envolved

NSRange with incorrect paremeters?

I am building this code to reverse a string, and all I need from you is why the parameters of the NSRange aren't working.
CODE:
for (int i = 0; i <= oldString.length; i++) {
NSRange range = NSMakeRange(i, oldString.length);
}
First of all your code is not sufficient, also if it work, doesn't do nothing.
Moreover, your app crash because NSRange takes 2 parameters: location and length.
So until location is 0, length can be oldString.length (i.e. all the string), otherwise, when location is > 0 and set as length oldString.length, it goes out of bounds.
Use this function where i use properly NSMakeRange as well:
- (NSString *)reverseString:(NSString *)string {
NSMutableString *newString = [NSMutableString new];
for (int i = (int)[string length]-1; i >= 0; i--) {
[newString appendString:[string substringWithRange:NSMakeRange(i, 1)]];
}
return [newString copy];
}
Your code is this:
for (int i = 0; i <= oldString.length; i++) {
NSRange range = NSMakeRange(i, oldString.length);
}
Now first of all, as Matteo has told you, it has no effect. All it does is make a bunch of ranges without using them.
But also let's look at those ranges! Just consider the successive values of range. Study your own code. Suppose our string oldString is 12345. Then its length is 5. Then the ranges would cover these strings in succession:
12345
2345[and one too far]
345[and two too far]
45[and three too far]
5[and four too far]
Those are pretty silly ranges!

Is it possible to do negative loc in the NSMakeRange?

Is it possible to do negative loc in the NSMakeRange?
NSString *string = #"abc";
NSString *myString = [string substringWithRange:NSMakeRange(-1, 1)];
No.
location and length are unsigned integers :
typedef struct _NSRange {
NSUInteger location;
NSUInteger length;
} NSRange;
and also, NSMakeRange function is defined as follow :
NSRange NSMakeRange (
NSUInteger loc,
NSUInteger len
);
Yes, it possible, but in fact it will no sense since negative value will translated to another very big positive value.
NSUInteger loc = -1; // equal to 4294967295
1.So, you are in need of a very long string.
2.So, you need to invert your negative value to enormous big value in order to make your example worked
NSString *string = #"abc";
NSRange r1 = NSMakeRange(-NSUIntegerMax, 1);
NSString *myString = [string substringWithRange:r1];
NSLog(#"%#",myString);

Resources