- 编码EMOJI表情字符串
OBJ-C:
扩展NSString
//编码EMOJI表情字符串
- (NSString *)encodeEmojiString {
NSMutableString *attributeString = [[NSMutableString alloc] initWithString:self];
NSString *regex_emoji = @"[\\ud83c\\udc00-\\ud83c\\udfff]|[\\ud83d\\udc00-\\ud83d\\udfff]|[\\ud83e\\udd00-\\ud83e\\udfff]|[\\u2600-\\u27ff]";
NSError *error = nil;
NSRegularExpression *re = [NSRegularExpression
regularExpressionWithPattern:regex_emoji
options:NSRegularExpressionCaseInsensitive
error:&error];
if (!re) {
DDLogInfo(@"[NSString toMessageString]: %@", [error localizedDescription]);
return attributeString;
}
DDLogInfo(@"stringToUnicode:%@,%@",[NSString stringToUnicode:attributeString],attributeString);
NSArray *resultArray = [re matchesInString:self options:0 range:NSMakeRange(0, self.length)];
NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:resultArray.count];
//根据匹配范围来用编码后的字符串进行相应的替换
for(NSTextCheckingResult *match in resultArray) {
//获取数组元素中得到range
NSRange range = [match range];
//获取原字符串中对应的值
NSString *subStr = [self substringWithRange:range];
//UTF8编码
NSString *credentialName = [NSString emojiConvert:subStr];
NSMutableDictionary *imageDic = [NSMutableDictionary dictionaryWithCapacity:2];
if (credentialName) {
[imageDic setObject:credentialName forKey:@"image"];
}
[imageDic setObject:[NSValue valueWithRange:range] forKey:@"range"];
//把字典存入数组中
[imageArray addObject:imageDic];
}
//从后往前替换,否则会引起位置问题
for (int i = (int)imageArray.count -1; i >= 0; i--) {
NSRange range = [imageArray[i][@"range"] rangeValue];
//进行替换
[attributeString replaceCharactersInRange:range withString:imageArray[i][@"image"]];
}
return attributeString;
}
//对emoji转码
- (NSString *)emojiConvert:(NSString *)obj {
DDLogInfo(@"stringToUnicode:对emoji转码");
NSString *charactersToEscape = @"?!@#$^&%*+,:;='\"`<>()[]{}/\\| ";
//invertedSet反转字符集,仅包含当前字符集中不存在的字符
NSCharacterSet *allowedCharacters = [[NSCharacterSet
characterSetWithCharactersInString:charactersToEscape] invertedSet];
NSString *encodeStr = [obj stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
NSString *result = [NSString stringWithFormat:@"<<%@>>", encodeStr];
return result;
}
Swift:
///编码EMOJI表情字符串
func encodeEmojiString() -> String {
let regex_emoji = "[\\ud83c\\udc00-\\ud83c\\udfff]|[\\ud83d\\udc00-\\ud83d\\udfff]|[\\ud83e\\udd00-\\ud83e\\udfff]|[\\u2600-\\u27ff]"
var regularExpression:NSRegularExpression?
do {
try regularExpression = NSRegularExpression(pattern: regex_emoji, options: .caseInsensitive)
} catch {
return self
}
guard let regularExpression = regularExpression else {
return self
}
let resultArray = regularExpression.matches(in: self, options: .reportProgress, range: NSMakeRange(0, self.count))
var imageArray:[Dictionary<String, Any>] = []
//根据匹配范围来用编码后的字符串进行相应的替换
for match in resultArray {
//获取数组元素中得到range
guard let range = toRange(match.range) else { return self }
//获取原字符串中对应的值
let subStr = self[range]
//对emoji转码
let charactersToEscape = "?!@#$^&%*+,:;='\"`<>()[]{}/\\| "
//invertedSet反转字符集,仅包含当前字符集中不存在的字符
let allowedCharacters = CharacterSet.init(charactersIn: charactersToEscape).inverted
let encodeStr = subStr.addingPercentEncoding(withAllowedCharacters: allowedCharacters)
let credentialName = "<<\(encodeStr ?? "")>>"
let imageDic = ["image":credentialName, "range":range] as [String : Any]
imageArray.append(imageDic)
}
var resultStr = self
//从后往前替换,否则会引起位置问题
for dict in imageArray.reversed() {
resultStr.replaceSubrange(dict["range"] as! Range<String.Index>, with: dict["image"] as! String)
}
return resultStr
}
- 解码EMOJI表情字符串
OBJ-C
扩展NSString
//解码EMOJI表情字符串
- (NSString *)decodeEmojiString {
NSMutableString *attributeString = [[NSMutableString alloc] initWithString:self];
NSString *regex_emoji = @"\\<\\<(.*?)\\>\\>";
NSError *error = nil;
NSRegularExpression *re = [NSRegularExpression
regularExpressionWithPattern:regex_emoji
options:NSRegularExpressionCaseInsensitive
error:&error];
if (!re) {
DDLogInfo(@"[NSString toMessageString]: %@", [error localizedDescription]);
return attributeString;
}
NSArray *resultArray = [re matchesInString:self options:0 range:NSMakeRange(0, self.length)];
NSMutableArray *imageArray = [NSMutableArray arrayWithCapacity:resultArray.count];
//根据匹配范围来用解码后的字符串进行相应的替换
for(NSTextCheckingResult *match in resultArray) {
//获取数组元素中得到range
NSRange range = [match range];
//获取原字符串中对应的值
NSString *subStr = [self substringWithRange:range];
//UTF8解码
NSString *credentialName = [NSString emojiRecovery:subStr];
NSMutableDictionary *imageDic = [NSMutableDictionary dictionaryWithCapacity:2];
if (credentialName) {
[imageDic setObject:credentialName forKey:@"image"];
}
[imageDic setObject:[NSValue valueWithRange:range] forKey:@"range"];
//把字典存入数组中
[imageArray addObject:imageDic];
}
//从后往前替换,否则会引起位置问题
for (int i = (int)imageArray.count -1; i >= 0; i--) {
NSRange range = [imageArray[i][@"range"] rangeValue];
//进行替换
[attributeString replaceCharactersInRange:range withString:imageArray[i][@"image"]];
}
return attributeString;
}
//对emoji解码
- (NSString *)emojiRecovery:(NSString *)obj {
DDLogInfo(@"stringToUnicode:对emoji解码");
//去除首尾指定字符串
NSCharacterSet *characterSet= [NSCharacterSet characterSetWithCharactersInString:@"<>"];
NSString *trimEndStr = [obj stringByTrimmingCharactersInSet:characterSet];
NSString *decodeStr = trimEndStr.stringByRemovingPercentEncoding;
if (StringNotEmpty(decodeStr)) {
return decodeStr;
} else {
return obj;
}
}
Swift:
也需要扩展NSString
extension NSString {
///解码EMOJI表情字符串
func decodeEmojiString() -> NSString {
let regex_emoji = "\\<\\<(.*?)\\>\\>"
var regularExpression:NSRegularExpression?
do {
try regularExpression = NSRegularExpression(pattern: regex_emoji, options: .caseInsensitive)
} catch {
return self
}
guard let regularExpression = regularExpression else {
return self
}
let resultArray = regularExpression.matches(in: (self as String), options: .reportProgress, range: NSMakeRange(0, self.length))
var imageArray:[Dictionary<String, Any>] = []
//根据匹配范围来用解码后的字符串进行相应的替换
for match in resultArray {
//获取数组元素中得到range
let range = match.range
//获取原字符串中对应的值
let subStr:NSString = self.substring(with: range) as NSString
//去除首尾指定字符串
let characterSet = CharacterSet.init(charactersIn: "<>")
let trimEndStr = subStr.trimmingCharacters(in: characterSet)
let decodeStr = trimEndStr.removingPercentEncoding
let imageDic = ["image":decodeStr ?? subStr, "range":range] as [String : Any]
imageArray.append(imageDic)
}
let resultStr:NSMutableString = NSMutableString.init(string: self)
//从后往前替换,否则会引起位置问题
for dict in imageArray.reversed() {
resultStr.replaceCharacters(in: dict["range"] as! NSRange, with: dict["image"] as! String)
}
return resultStr
}
}
Swift中用到的扩展:
extension String {
//Range转换为NSRange
func toNSRange(_ range: Range<String.Index>) -> NSRange {
guard let from = range.lowerBound.samePosition(in: utf16), let to = range.upperBound.samePosition(in: utf16) else {
return NSMakeRange(0, 0)
}
return NSMakeRange(utf16.distance(from: utf16.startIndex, to: from), utf16.distance(from: from, to: to))
}
//NSRange转换为Range
func toRange(_ range: NSRange) -> Range<String.Index>? {
let indexStart = self.index(self.startIndex, offsetBy: range.location)
let indexEnd = self.index(indexStart, offsetBy: range.length)
return indexStart..<indexEnd
}
}
- 总结
坑:
某些Emoji例如💁♀️,就是💁+♀,采用变型表单,为那些可以显示颜色和其他内容的显示器提供更多信息。
其中♀前后都有不可见字符,用来表示♀是需要和💁合并的。表示形式为:\u200d
♀\ufe0f
而我们在编码Emoji时,将Emoji用<<>>括起来进行发送。
其中Swift语言编码的String,会将>
这个符号和表情带的\u200d
与\ufe0f
结合
上图就可以清楚的看出其中的不同。
转换成Unicode↓
字符 | 转Unicode |
---|---|
💁♀️ | \ud83d\udc81\u200d\u2640\ufe0f |
💁 | \ud83d\udc81 |
单个♀ | \u2640 |
用于表示Emoji更多信息的♀ | \u200d\u2640\ufe0f |
> | \u0026\u0067\u0074\u003b |
> | \u0026\u0067\u0074\u003b\u200d |
> | \u0026\u0067\u0074\u003b\ufe0f |
所以在实际使用时,使用NSString来代替String。