Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Remove Emoji in NSString
// XCode 4.2.1
@implementation NSString(EmojiExtension)
- (NSString*)removeEmoji {
__block NSMutableString* temp = [NSMutableString string];
[self enumerateSubstringsInRange: NSMakeRange(0, [self length]) options:NSStringEnumerationByComposedCharacterSequences usingBlock:
^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop){
const unichar hs = [substring characterAtIndex: 0];
// surrogate pair
if (0xd800 <= hs && hs <= 0xdbff) {
const unichar ls = [substring characterAtIndex: 1];
const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
[temp appendString: (0x1d000 <= uc && uc <= 0x1f77f)? @"": substring]; // U+1D000-1F77F
// non surrogate
} else {
[temp appendString: (0x2100 <= hs && hs <= 0x26ff)? @"": substring]; // U+2100-26FF
}
}];
return temp;
}
@end
@DHowett

This comment has been minimized.

Copy link

@DHowett DHowett commented Aug 1, 2014

Why muck about with surrogate pairs and blocks (and function call overhead) if you don't have to?

#include <unicode/utf8.h>
@implementation NSString (EmojiExtension)
- (NSString *)stringByRemovingEmoji {
    NSData *d = [self dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:NO];
    if(!d) return nil;
    const char *buf = d.bytes;
    unsigned int len = [d length];
    char *s = (char *)malloc(len);
    unsigned int ii = 0, oi = 0; // in index, out index
    UChar32 uc;
    while (ii < len) {
        U8_NEXT_UNSAFE(buf, ii, uc);
        if(0x2100 <= uc && uc <= 0x26ff) continue;
        if(0x1d000 <= uc && uc <= 0x1f77f) continue;
        U8_APPEND_UNSAFE(s, oi, uc);
    }
    return [[[NSString alloc] initWithBytesNoCopy:s length:oi encoding:NSUTF8StringEncoding freeWhenDone:YES] autorelease];
}
@end

(Gist'd here)

@nschum

This comment has been minimized.

Copy link

@nschum nschum commented May 1, 2015

Swift version:

extension Character {
    func isEmoji() -> Bool {
        return Character(UnicodeScalar(0x1d000)) <= self && self <= Character(UnicodeScalar(0x1f77f))
            || Character(UnicodeScalar(0x2100)) <= self && self <= Character(UnicodeScalar(0x26ff))
    }
}

extension String {
    func stringByRemovingEmoji() -> String {
        return String(filter(self, {c in !c.isEmoji()}))
    }
}
@deya-eldeen

This comment has been minimized.

Copy link

@deya-eldeen deya-eldeen commented Jun 19, 2016

thanks nschum, but this is not working for swift 2.2, there is a problem in
c.isEmoji()

@crazypepper

This comment has been minimized.

Copy link

@crazypepper crazypepper commented Jul 12, 2016

For Swift 2.2:

extension Character {
    func isEmoji() -> Bool {
        return Character(UnicodeScalar(0x1d000)) <= self && self <= Character(UnicodeScalar(0x1f77f))
            || Character(UnicodeScalar(0x2100)) <= self && self <= Character(UnicodeScalar(0x26ff))
    }
}

extension String {
    func stringByRemovingEmoji() -> String {
        return String(self.characters.filter{!$0.isEmoji()})
    }
}
@foffer

This comment has been minimized.

Copy link

@foffer foffer commented Dec 9, 2016

Swift 3.0

extension Character {
    fileprivate func isEmoji() -> Bool {
        return Character(UnicodeScalar(UInt32(0x1d000))!) <= self && self <= Character(UnicodeScalar(UInt32(0x1f77f))!) 
            || Character(UnicodeScalar(UInt32(0x2100))!) <= self && self <= Character(UnicodeScalar(UInt32(0x26ff))!)
    }
}

extension String {
    func stringByRemovingEmoji() -> String {
        return String(self.characters.filter { !$0.isEmoji() })
    }
}
@deya-eldeen

This comment has been minimized.

Copy link

@deya-eldeen deya-eldeen commented May 3, 2017

in XCode 8.3.2 ...

func stringByRemovingEmoji() -> String {
    return String(self.characters.filter { !$0.isEmoji() })
}

no longer works.

@maira786

This comment has been minimized.

Copy link

@maira786 maira786 commented Nov 26, 2017

Swift 4.0

extension Character {
    fileprivate func isEmoji() -> Bool {
        return Character(UnicodeScalar(UInt32(0x1d000))!) <= self && self <= Character(UnicodeScalar(UInt32(0x1f77f))!) 
            || Character(UnicodeScalar(UInt32(0x2100))!) <= self && self <= Character(UnicodeScalar(UInt32(0x26ff))!)
    }
}

extension String {
    func stringByRemovingEmoji() -> String {
        return String(self.filter { !$0.isEmoji() })
    }
}
@simon9211

This comment has been minimized.

Copy link

@simon9211 simon9211 commented May 2, 2018

the emoj of heart ❤️ does not work!

@Anticro

This comment has been minimized.

Copy link

@Anticro Anticro commented Jul 1, 2020

'Measuring length of a string' at the Apple docs https://developer.apple.com/documentation/swift/string brought me to another solution, without the need for knowledge about the unicode pages. I just want letters to to remain in the string and skip all that is an icon:

#include <string.h>

inline static NSString* _Nonnull nsstring_remove_emoji_v2(NSString* const _Nonnull origString) {
    NSMutableString* const result = [NSMutableString stringWithCapacity:0];
    NSUInteger const len = origString.length;
    NSString* subStr;
    for (NSUInteger index = 0; index < len; index++) {
        subStr = [origString substringWithRange:NSMakeRange(index, 1)];
        const char* utf8Rep = subStr.UTF8String;  // will return NULL for icons that consist of 2 chars
        if (utf8Rep != NULL) {
            unsigned long const length = strlen(utf8Rep);
            if (length <= 2) {
                [result appendString:subStr];
            }
        }
    }
    return result.copy;
}

I have no clue, what this does with chinese or japanese text. But it works for all german letters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.