Can you split a NSString into an NSArray of strings based on a content size? - iphone

Basically i want to pass an NSString and a CGSize (the content size) and get an NSArray of NSStrings that will fit into this content size.
So for instance i have #"something really long" and specify a size CGSizeMake(20, 10), i would get back a NSArray of [#"something", #" really", #" long"] for example.
Anyone have any ideas / sample code?

Not sure this is that straight forward. Is the CGSize enough? Does not the amount of text that can fit inside a contentSize depend on the fontSize too? Not sure you would want to do all this. It can get pretty complex. Dont see the need for all that.
Instead define some comfortable contentSize for your UILabel & truncate the rest or even better opt for Adjust to Fit along with defining a min. font size. With this iOS will try its best to fit your text keeping in mind the min font size. Here's how to do it in IB -

Assuming that you want to break by words (break where there is a space) here is a psuedo-code algorithm:
1) Get Width as parameter
2) Declare String temp, int breakPoint, array list
3) For Each (character in String)
Add character to temp String
if (character is space)
set breakPoint to currentIndexInTemp
end if
if (temp String size > Width OR character is newline)
declare String newString
set newString equal to substring of temp(from 0 to breakPoint)
add newString to list
set temp to substring of temp(from breakPoint + 1 to end)
reset breakPoint
end if
end For Each
4) if (length of temp > 0)
add temp to list
end if
5) return list
I'm sorry if that's terrible pseudo-code, I don't write pseudo-code often (actually, at all) and I'm not familiar enough with Objective-C to write it in the language.
NOTE
The breakPoint is the last occurrence of a space, or break in
characters, if the length is too long then you want to cut at the
breakPoint to prevent chopping words. This is the index in the
temp String only, not the String you're breaking up.
There may be a simpler way to to do this in Objective-C, I don't know, this algorithm is based off a function I wrote in Java to break a string into 80 character lines.
EDIT
Added New Line testing. In my example, if it's a new line then break it there whether it's too long or not. Also, when you break the String into an array (the second if) you'll want to reset the breakPoint variable. I'd also agree that for overly large portions of text this will add overhead, I've not had issues with text-processing of several hundred characters. Although that was done on a desktop/laptop program.

Related

How do I use length() for unicode characters?

When working in the Moovweb SDK, length("çãêá") is expected to return 4, but instead returns 8. How can I ensure that the length function works correctly when using Unicode characters?
This is a common issue with Unicode characters and the length() function using the wrong character set. To fix it you need to set the charset_determined variable to make sure the correct character set is being used before making the call to length(), like so in your tritium code:
$charset_determined = "utf-8"
# your call to length() here
In Unicode, there is no such thing as a length of a string or "number of characters". All this comes from ASCII thinking.
You can choose from one of the following, depending what you exactly need:
For cursor movement, text selection and alike, grapheme clusters shall be used.
For limiting the length of a string in input fields, file formats, protocols, or databases, the length is measured in code units of some predetermined encoding. The reason is that any length limit is derived from the fixed amount of memory allocated for the string at a lower level, be it in memory, disk or in a particular data structure.
The size of the string as it appears on the screen is unrelated to the number of code points in the string. One has to communicate with the rendering engine for this. Code points do not occupy one column even in monospace fonts and terminals. POSIX takes this into account.
There is more info in http://utf8everywhere.org

How to remove the last unicode symbol from NSString

I have implemented a custom keyboard associated with a text field, so when the user presses the delete button, I remove the last character from the string, and manually update the current text field text.
NSRange range = NSMakeRange(currentTextFieldString.length-1, 1);
[currentTextFieldString replaceCharactersInRange:range withString:#""];
So far so good.
Now, the problem is, that the user has the option to enter some special unicode symbols, these are not 1 byte, they can be 2 bytes too, now on pressing the delete button, I have to remove the entire symbol, but if I follow the above approach, the user has to press the delete button twice.
Here, if I do:
NSRange range = NSMakeRange(currentTextFieldString.length-2, 2);
[currentTextFieldString replaceCharactersInRange:range withString:#""];
it works fine, but then, the normal characters, which are just 1 byte, get deleted twice at a time.
How to handle such scenarios?
Thanks in advance.
EDIT:
It is strange, that if I switch to the iPhone keyboard, it handles both cases appropriately. There must be some way to do it, there is something that I am missing, but am not able to figure out what.
Here's the problem. NSStrings are encoded using UTF-16. Many common Unicode glyphs take up only one unichar (a 16 bit unsigned value). However, some glyphs take up two unichars. Even worse, some glyphs can be composed or decomposed, e.g.é might be one Unicode code point or it might be two - an acute accent followed by an e. This makes it quite difficult to do what you want viz delete one "character" because it is really hard to tell how many unichars it takes up.
Fortunately, NSString has a method that helps with this: -rangeOfComposedCharacterSequenceAtIndex:. What you need to do is get the index of the last unichar, run this method on it, and the returned NSRange will tell you where to delete from. It goes something like this (not tested):
NSUInteger lastCharIndex = [myString length] - 1; // I assume string is not empty
NSRange rangeOfLastChar = [myString rangeOfComposedCharacterSequenceAtIndex: lastCharIndex];
myNewString = [myString substringToIndex: rangeOfLastChar.location];
If you can't get this to work by default, then use an if/else block and test if the last character is part of a special character. If it is, use the substring to length-2, otherwise use the substring to length-1.
I don't know exactly what the problem is there with the special characters byte length.
What i suggest is:
Store string length to a param, before adding any new characters
If user selects backspace (remove last characters) then remove the string from last length to new length. Means for example last saved string length is 5 and new string length is 7 then remove get a new string with the index from 0 to 4, so it will crop the remaining characters.
This is the other way around to do as i don't know the exact what problem internally.
But i guess logically this solution should work.
Enjoy Coding :)

UILabel truncation " ..." (space + ...) instead of "..."

So I am trying to implement UILabel with UILineBreakModeTailTruncation.
So, for example if the text is "StackOverflow is the best website for programmers", it gets truncated as "StackOverflow is the best..."
It needs to be "StackOverflow is the best ..." (Space + ...)
Is there any easy way to implement this ??
Any easy implementations other than subclassing & overriding drawRect, and/or playing around with the frames, (if it character limit frame size, stop it and append " ...") ??
Look forward to interesting implementations !
As far as I know, Apple does not provide any API for this. You have to write your own implementation. I would calculate the width of the UILabel with the current font, see if it exceeds the maximum width, if it does, truncate text, otherwise present text normally.

UILabel.text shortening and appending "..."

I have an UILabel that I want to contain a preview of a long string. It should be a 1-line-label, and should be populated with a maximum number of Characters and then append "..." at the end of the UILabel.text. Now i could do that manually, but I'd really like to calculate all of that stuff and do it dynamically, as the label is a subview of UITableViewCell and when turning the device, it should be possible to stretch it and calculate again.
Any ideas?
P.S. Sorry for any spelling mistakes, I'm not a native speaker..
I'm not sure if I understand your question well, but isn't this supported anyway, if you set the UILabel's lineBreakMode to UILineBreakModeTailTruncation?

How to replace variables in an html file which is feeded to an UIWebView?

In my app, I want to replace some variables inside an html file when it goes to an UIWebView. The file is local. For example, I add a variable $userName$ and then I would replace that with #"John".
Would I have to read the file in as string, and then perform some string replacement action?
Yes, that should work... take a look at the replaceOccurrencesOfString:withString:options:range: method of NSMutableString. If there is much content and the position of your variable is not known exactly but is to be expected within known limits (for example within the first 100 characters), you might want to provide a range to reduce the overhead from comparing the whole content to the term you're about to replace. If the position of the variable is fixed, you could use replaceCharactersInRange:withString: instead. This would eliminate the performance penalty of comparing every part of the string to the string you're about to replace completely.