Trim last two lines of an attributed string - ios

How do I remove the last two lines of this NSAttributedString?
NSString *exampleString = #"line 1\nline 2\nline 3\nline 4"
NSAttributedString *as = [NSAttributedString alloc] int];
[as setString:exampleString];
[self removeLastTwoLinesOfAttributedString:as];
NSLog(#"%#",as);
-(void)removeLastTwoLinesOfAttributedString:(NSAttributedString *)string {
//some code here
}
I'd like to end up with #"line 1\nline 2" in this example. Thanks

You could do something like this :
-(NSAttributedString *) removeLastTwoLinesOfAttributedString:(NSAttributedString *aString) {
NSRange range = [aString.string rangeOfString:#"\n" options:NSBackwardsSearch];
range = [aString.string rangeOfString:#"\n" options:NSBackwardsSearch range:NSMakeRange(0, range.location)];
return [aString attributedSubstringFromRange:NSMakeRange(0, range.location)];
}
int main (int argc, const char * argv[])
{
NSString *exampleString = #"line 1\nline 2\nline 3\nline 4";
NSAttributedString *as = [[NSAttributedString alloc] initWithString:exampleString];
as = [self removeLastTwoLinesOfAttributedString:as];
NSLog(#"%#",as);
return 0;
}
Output
line 1
line 2

I would suggest as the best solution:
-(NSAttributedString *)removeLastTwoLinesOfAttributedString:(NSAttributedString *)aString {
if (aString.length == 0) {
return aString
}
NSString *string = [aString string];
unsigned numberOfLines, index, stringLength = [string length];
NSRange rangeOfLastTwoLines = NSMakeRange(aString.length - 1, 0);
for (index = stringLength-1, numberOfLines = 0; index >= 0 && numberOfLines < 2; numberOfLines++) {
NSRange rangeOfLine = [string lineRangeForRange:NSMakeRange(index, 0)];
rangeOfLastTwoLines = NSUnionRange(rangeOfLastTwoLines, rangeOfLine);
index -= rangeOfLine.length;
}
return [aString attributedSubstringFromRange:NSMakeRange(0, rangeOfLastTwoLines.location)];
}
This has the benefit of working with any newline character not just "\n" and it uses the preferred by Apple method for detecting lines see this
Also it will not break if the last two lines are less than 2

If you're using Swift you can do this, if you're using Objective-C you should look at the other answers.
You can drop the last two lines of a String like this
string.components(separatedBy: "\n").dropLast(2).joined(separator: "\n")
To do it to an attributed string just access the string property, remove the last two lines, and create an attributed string with the trimmed string and all the same attributes.

Related

Get string between strings with multiple occurrences

I found a lot of examples how to find string between 2 strings, but none of which shows how to handle multiple occurrences of that string. I have for example string like this
"Hi, I am <id>User</id>. I am 20 <id>years old</id>, and live in <id>some country</id>."
The idea behind is that I want to hyperlink each occurrence of that string within UITextField, and remove tags from the string. I also have 2 types of the tag, one should display hyperlink, the other should popup alert view with some text description of the word or phrase clicked.
EDIT:
Found a perfectly good working solution to extend this logic with changing content of the text with attributed string between tags provided in the text. Link here.
#Aleksandar Try this.. it works for me..
NSString *serverOutput = #"Hi, I am <id>User</id>. I am 20 <id>years old</id>, and live in <id>some country</id>.";
if([serverOutput containsString:#"</id>"])
{
NSArray *arrSeparate = [serverOutput componentsSeparatedByString:#"</id>"];
NSString *output = #"";
for(int i=0; i<arrSeparate.count; i++)
{
if([[arrSeparate objectAtIndex:i] containsString:#"<id>"])
{
NSArray *arrTest = [[arrSeparate objectAtIndex:i] componentsSeparatedByString:#"<id>"];
if(output.length < 1)
output = [arrTest objectAtIndex:1];
else
output = [NSString stringWithFormat:#"%#\n%#",output,[arrTest objectAtIndex:1]];
}
}
serverOutput = output;
}
NSLog(#"%#", serverOutput);
Please look into this, and i hope this gets you all the range where the keyword exists
NSString *serverOutput = #"Hi, I am <id>User</id>. I am 20 <id>years old</id>, and live in <id>some country</id>";
NSUInteger count = 0, length = [serverOutput length];
NSRange startRange = NSMakeRange(0, length);
NSRange endRange = NSMakeRange(0, length);
while(startRange.location != NSNotFound)
{
startRange = [serverOutput rangeOfString: #"<id>" options:0 range:startRange];
if(startRange.location != NSNotFound)
{
endRange = [serverOutput rangeOfString: #"</id>" options:0 range:endRange];
startRange = NSMakeRange(startRange.location + startRange.length, length - (startRange.location + startRange.length));
endRange = NSMakeRange(endRange.location + endRange.length, length - (endRange.location + endRange.length));
count++;
}
}
startRange will be the range from where the tag starts and endRange is where starts
You can change the range, location, create attributed string and add hyperlink as the range of string is available to you.

Transform punctuations form half width to full width

I have a sentence below:
我今天去买菜,买了一个西瓜,花了1.2元,买了一个土豆,花了3.78元。还买了一个无花果,花了45.89,怎么办呢?好贵呀!贵的我不知道再买什么了。
The punctuations in it are half width. How to change them to fullwidth, like the following:
我今天去买菜,买了一个西瓜,花了1.2元,买了一个土豆,花了3.78元。还买了一个无花果,花了45.89,怎么办呢?好贵呀!贵的我不知道再买什么了。
Some punctuations to consider (not exhaustive):
, to ,
? to ?
! to !
"" to “”
; to ;
First, define the CharacterSet from which you want to transform your characters. So if you want only punctuation, the set could be CharacterSet.punctuationCharacters or CharacterSet.alphanumerics.inverted.
Then map each character from this set to its HalfwidthFullwidth transformation.
Swift 3 and 4
extension String {
func transformingHalfwidthFullwidth(from aSet: CharacterSet) -> String {
return String(characters.map {
if String($0).rangeOfCharacter(from: aSet) != nil {
let string = NSMutableString(string: String($0))
CFStringTransform(string, nil, kCFStringTransformFullwidthHalfwidth, true)
return String(string).characters.first!
} else {
return $0
}
})
}
}
Usage
let string = ",?!\"\";abc012図書館 助け 足場が痛い 多くの涙"
let result = string.transformingHalfwidthFullwidth(from: CharacterSet.alphanumerics.inverted)
// it prints: ,?!"";abc012図書館 助け 足場が痛い 多くの涙
print(result)
Objective-C
#implementation NSString (HalfwidthFullwidth)
- (NSString *)transformingHalfwidthFullwidth:(nonnull NSCharacterSet *)aSet {
NSUInteger len = self.length;
unichar buffer[len + 1];
[self getCharacters:buffer range:NSMakeRange(0, len)];
for (int i = 0; i < len; i++) {
unichar c = buffer[i];
NSMutableString *s = [[NSMutableString alloc] initWithCharacters:&c length:1];
NSRange r = [s rangeOfCharacterFromSet:aSet];
if (r.location != NSNotFound) {
CFStringTransform((CFMutableStringRef)s, nil, kCFStringTransformFullwidthHalfwidth, true);
[s getCharacters:buffer + i range:NSMakeRange(0, 1)];
}
}
return [NSString stringWithCharacters:buffer length:len];
}
#end
Usage
NSString *string = #",?!\"\";abc012図書館 助け 足場が痛い 多くの涙";
NSString *result = [string transformingHalfwidthFullwidth:NSCharacterSet.alphanumericCharacterSet.invertedSet];
// it prints: ,?!"";abc012図書館 助け 足場が痛い 多くの涙
NSLog(result);
you can use CFStringTransform like :
Objective C :
NSString *string = #" ? \"\"!我今天去买菜,买了一个西瓜,花了1.2元,买了一个土豆,花了3.78元。还买了一个无花果,花了45.89,怎么办呢?好贵呀!贵的我不知道再买什么了";
NSMutableString *convertedString = [string mutableCopy];
CFStringTransform((CFMutableStringRef)convertedString, NULL, kCFStringTransformFullwidthHalfwidth, true);
NSLog(#"%#",convertedString);
Swift 3.0 :
let string = NSMutableString( string: " ? \"\"!我今天去买菜,买了一个西瓜,花了1.2元,买了一个土豆,花了3.78元。还买了一个无花果,花了45.89,怎么办呢?好贵呀!贵的我不知道再买什么了" )
CFStringTransform( string, nil, kCFStringTransformFullwidthHalfwidth, true )
print(string)

NSString to treat "regular english alphabets" and characters like emoji or japanese uniformly

There is a textView in which I can enter Characters. characters can be a,b,c,d etc or a smiley face added using emoji keyboard.
-(void)textFieldDidEndEditing:(UITextField *)textField{
NSLog(#"len:%lu",textField.length);
NSLog(#"char:%c",[textField.text characterAtIndex:0]);
}
Currently , The above function gives following outputs
if textField.text = #"qq"
len:2
char:q
if textField.text = #"😄q"
len:3
char:=
What I need is
if textField.text = #"qq"
len:2
char:q
if textField.text = #"😄q"
len:2
char:😄
Any clue how to do this ?
Since Apple screwed up emoji (actually Unicode planes above 0) this becomes difficult. It seems it is necessary to enumerate through the composed character to get the actual length.
Note: The NSString method length does not return the number of characters but the number of code units (not characters) in unichars. See NSString and Unicode - Strings - objc.io issue #9.
Example code:
NSString *text = #"qqq😄rrr";
int maxCharacters = 4;
__block NSInteger unicharCount = 0;
__block NSInteger charCount = 0;
[text enumerateSubstringsInRange:NSMakeRange(0, text.length)
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
unicharCount += substringRange.length;
if (++charCount >= maxCharacters)
*stop = YES;
}];
NSString *textStart = [text substringToIndex: unicharCount];
NSLog(#"textStart: '%#'", textStart);
textStart: 'qqq😄'
An alternative approach is to use utf32 encoding:
int byteCount = maxCharacters*4; // 4 utf32 characters
char buffer[byteCount];
NSUInteger usedBufferCount;
[text getBytes:buffer maxLength:byteCount usedLength:&usedBufferCount encoding:NSUTF32StringEncoding options:0 range:NSMakeRange(0, text.length) remainingRange:NULL];
NSString * textStart = [[NSString alloc] initWithBytes:buffer length:usedBufferCount encoding:NSUTF32LittleEndianStringEncoding];
There is some rational for this in Session 128 - Advance Text Processing from 2011 WWDC.
This is what i did to cut a string with emoji characters
+(NSUInteger)unicodeLength:(NSString*)string{
return [string lengthOfBytesUsingEncoding:NSUTF32StringEncoding]/4;
}
+(NSString*)unicodeString:(NSString*)string toLenght:(NSUInteger)len{
if (len >= string.length){
return string;
}
NSInteger charposition = 0;
for (int i = 0; i < len; i++){
NSInteger remainingChars = string.length-charposition;
if (remainingChars >= 2){
NSString* s = [string substringWithRange:NSMakeRange(charposition,2)];
if ([self unicodeLength:s] == 1){
charposition++;
}
}
charposition++;
}
return [string substringToIndex:charposition];
}

How to display hyphen in uilabel?

How to display hyphen with UILabel like this, - A I origine - , Here I use the string appending method. I get this type of output - À l'origine de la guerre -. But I want display hyphen before the starting point of text and display hyphen after 10 charatcers.
I was searched but i can't get valied source. kindly give any suggestion if you know.
NSString *tempStr = #" - ";
tempStr = [tempStr stringByAppendingString:NSLocalizedString(#"OriginallyWar", #"")];
tempStr = [tempStr stringByAppendingString:#" -"];
[headingLabel setText:tempStr];
[headingLabel setFont:MRSEAVES_BOLD(17)];
Use NSMutableString and insert characters,
[yourString insertString:#"-" atIndex:10];
if you are using StoryBoard directly set it to the text property on Attribute inspector. Put 10 empty spaces after the end of character and the -.
You may try this code
NSString *inputString = #"OriginallyWarDFdfsdfdDFSDfdsfdsfDFdsfadsfawerdsaf";
NSMutableString *localizedInputString = [NSMutableString stringWithString:NSLocalizedString(inputString, #"")];
int numberOfCharacters = localizedInputString.length;
int numberOf10s = (numberOfCharacters/10 + 1);
int numberOfCharactersToBeInserted = 0;
for (int i = 1; i < numberOf10s; i++) {
int characterIndex = (i * 10) + numberOfCharactersToBeInserted;
if (i == (numberOf10s - 1) && numberOfCharacters % 10 == 0) {
[localizedInputString insertString:#" -" atIndex:characterIndex];
numberOfCharactersToBeInserted = 2 * i;
} else {
[localizedInputString insertString:#" - " atIndex:characterIndex];
numberOfCharactersToBeInserted = 3 * i;
}
}
if (numberOfCharacters == 0) {
[localizedInputString insertString:#"-" atIndex:0];
} else {
[localizedInputString insertString:#"- " atIndex:0];
}
NSLog(#"localizedInputString : %#", localizedInputString);
try using NSMutableString
NSString *tempStr = #" - ";
tempStr = [tempStr stringByAppendingString:NSLocalizedString(#"OriginallyWar", #"")];
NSMutableString *tempStrMutable=[[NSMutableString alloc]initWithString:tempStr];
[tempStrMutable insertString:#"-" atIndex:10];
[headingLabel setText:tempStrMutable];

How to split string into substrings on iOS?

I received an NSString from the server. Now I want to split it into the substring which I need.
How to split the string?
For example:
substring1:read from the second character to 5th character
substring2:read 10 characters from the 6th character.
You can also split a string by a substring, using NString's componentsSeparatedByString method.
Example from documentation:
NSString *list = #"Norman, Stanley, Fletcher";
NSArray *listItems = [list componentsSeparatedByString:#", "];
NSString has a few methods for this:
[myString substringToIndex:index];
[myString substringFromIndex:index];
[myString substringWithRange:range];
Check the documentation for NSString for more information.
I wrote a little method to split strings in a specified amount of parts.
Note that it only supports single separator characters. But I think it is an efficient way to split a NSString.
//split string into given number of parts
-(NSArray*)splitString:(NSString*)string withDelimiter:(NSString*)delimiter inParts:(int)parts{
NSMutableArray* array = [NSMutableArray array];
NSUInteger len = [string length];
unichar buffer[len+1];
//put separator in buffer
unichar separator[1];
[delimiter getCharacters:separator range:NSMakeRange(0, 1)];
[string getCharacters:buffer range:NSMakeRange(0, len)];
int startPosition = 0;
int length = 0;
for(int i = 0; i < len; i++) {
//if array is parts-1 and the character was found add it to array
if (buffer[i]==separator[0] && array.count < parts-1) {
if (length>0) {
[array addObject:[string substringWithRange:NSMakeRange(startPosition, length)]];
}
startPosition += length+1;
length = 0;
if (array.count >= parts-1) {
break;
}
}else{
length++;
}
}
//add the last part of the string to the array
[array addObject:[string substringFromIndex:startPosition]];
return array;
}

Resources