Search code examples
swiftstringuilabelnsattributedstringemoji

change string with picture in swift


I have a String in a UILabel and this string includes one or several emoji but only the name like ":cool:" or ":crazy:".

How can I replace the word in the String with the .png ?

func checkString(pString: String) -> String {

    var replaced = pString //get the String
    var found = ""
    var image = UIImage() //Emoji

    for i in 1...bib.count { //bib = array(Int:String) with all names of the Emoji
        if pString.range(of: bib[i]!) != nil {
            found = bib[I]!

            //picBib is a array(String:String) with the Emoji name and the path

            if let picURL: String = picBib[found] as? String {
                image = UIImage(named: picURL)!
            }
            //cute the ":cool:" out of the String
            replaced = pString.replacingOccurrences(of: found, with: "")
            let imageView = UIImageView(image: image)
            imageView.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
        }
    }
    return replaced
}

I think there is a better way for something like this.. the Emoji are not in a library. I have them in a JSON {";P":";P.png",":)":"colon_).png" ...

maybe I have to switch from UILabel to .. ?


Solution

  • Not tested, but that should do the trick:

    let string = "Hello :cool:, no? What a :crazy: day!"
    let emojiDict: [String: String] = [":cool:": "cool.png", ":crazy:": "crazy.png"]
    
    let attributedString = NSMutableAttributedString(string: string)
    
    for (anEmojiTag, anEmojiImageName) in emojiDict {
        let pattern = NSRegularExpression.escapedPattern(for: anEmojiTag)
        let regex = try? NSRegularExpression(pattern: pattern,
                                             options: [])
        if let matches = regex?.matches(in: attributedString.string,
                                        options: [],
                                        range: NSRange(location: 0, length: attributedString.string.utf16.count)) {
            for aMatch in matches.reversed() {
                let attachment = NSTextAttachment()
                attachment.image = UIImage(named: anEmojiImageName)
                //attachment.bounds = something //if you need to resize your images
                let replacement = NSAttributedString(attachment: attachment)
                attributedString.replaceCharacters(in: aMatch.range, with: replacement)
            }
        }
    }
    
    myLabel.attributedText = attributedString
    

    What's the idea:
    Use NS(Mutable)AttributedString to be able to put images into a text
    Use NSRegularExpression to find all the occurrences
    Replace values starting from the end (else, all the ranges found will might be broken, because the length of the occurrence and the replacement will not be the same.

    Edit: Quickly written in Objective-C (not checked)

    NSString *string = @"Hello :cool:, no? What a :crazy: day!";
    NSDictionary *emojiDict = @{@":cool:": @"cool.png", @":crazy:": @"crazy.png"};
    
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string];
    
    for (NSString *anEmojiText in emojiDict)
    {
        NSString *anEmojiImageName = emojiDict[anEmojiText];
        NSString *pattern = [NSRegularExpression escapedPatternForString:anEmojiText];
        NSError *regexError = nil;
        NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:&regexError];
        if (regexError) { /* Error management missing here */ }
        NSArray *matches = [regex matchesInString:[attributedString string] options:0 range:NSMakeRange(0, [attributedString length])];
    
        [matches enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(NSTextCheckingResult * _Nonnull aResult, NSUInteger idx, BOOL * _Nonnull stop) {
            NSTextAttachment *attachment = [[NSTextAttachment alloc] init];
            [attachment setImage:[UIImage imageNamed:anEmojiImageName]];
            //[attachment setBounds:something]; //if you need to resize your images
            NSAttributedString *replacement = [NSAttributedString attributedStringWithAttachment:attachment];
            [attributedString replaceCharactersInRange:[aResult range] withAttributedString:replacement];
        }];
    }
    
    [myLabel setAttributedText:attributedString];