- 編碼EMOJI表情字符串
OBJ-C:
擴(kuò)展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];
//根據(jù)匹配范圍來(lái)用編碼后的字符串進(jìn)行相應(yīng)的替換
for(NSTextCheckingResult *match in resultArray) {
//獲取數(shù)組元素中得到range
NSRange range = [match range];
//獲取原字符串中對(duì)應(yīng)的值
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"];
//把字典存入數(shù)組中
[imageArray addObject:imageDic];
}
//從后往前替換,否則會(huì)引起位置問(wèn)題
for (int i = (int)imageArray.count -1; i >= 0; i--) {
NSRange range = [imageArray[i][@"range"] rangeValue];
//進(jìn)行替換
[attributeString replaceCharactersInRange:range withString:imageArray[i][@"image"]];
}
return attributeString;
}
//對(duì)emoji轉(zhuǎn)碼
- (NSString *)emojiConvert:(NSString *)obj {
DDLogInfo(@"stringToUnicode:對(duì)emoji轉(zhuǎn)碼");
NSString *charactersToEscape = @"?!@#$^&%*+,:;='\"`<>()[]{}/\\| ";
//invertedSet反轉(zhuǎn)字符集瑟匆,僅包含當(dāng)前字符集中不存在的字符
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>] = []
//根據(jù)匹配范圍來(lái)用編碼后的字符串進(jìn)行相應(yīng)的替換
for match in resultArray {
//獲取數(shù)組元素中得到range
guard let range = toRange(match.range) else { return self }
//獲取原字符串中對(duì)應(yīng)的值
let subStr = self[range]
//對(duì)emoji轉(zhuǎn)碼
let charactersToEscape = "?!@#$^&%*+,:;='\"`<>()[]{}/\\| "
//invertedSet反轉(zhuǎn)字符集工闺,僅包含當(dāng)前字符集中不存在的字符
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
//從后往前替換错沽,否則會(huì)引起位置問(wèn)題
for dict in imageArray.reversed() {
resultStr.replaceSubrange(dict["range"] as! Range<String.Index>, with: dict["image"] as! String)
}
return resultStr
}
- 解碼EMOJI表情字符串
OBJ-C
擴(kuò)展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];
//根據(jù)匹配范圍來(lái)用解碼后的字符串進(jìn)行相應(yīng)的替換
for(NSTextCheckingResult *match in resultArray) {
//獲取數(shù)組元素中得到range
NSRange range = [match range];
//獲取原字符串中對(duì)應(yīng)的值
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"];
//把字典存入數(shù)組中
[imageArray addObject:imageDic];
}
//從后往前替換锰霜,否則會(huì)引起位置問(wèn)題
for (int i = (int)imageArray.count -1; i >= 0; i--) {
NSRange range = [imageArray[i][@"range"] rangeValue];
//進(jìn)行替換
[attributeString replaceCharactersInRange:range withString:imageArray[i][@"image"]];
}
return attributeString;
}
//對(duì)emoji解碼
- (NSString *)emojiRecovery:(NSString *)obj {
DDLogInfo(@"stringToUnicode:對(duì)emoji解碼");
//去除首尾指定字符串
NSCharacterSet *characterSet= [NSCharacterSet characterSetWithCharactersInString:@"<>"];
NSString *trimEndStr = [obj stringByTrimmingCharactersInSet:characterSet];
NSString *decodeStr = trimEndStr.stringByRemovingPercentEncoding;
if (StringNotEmpty(decodeStr)) {
return decodeStr;
} else {
return obj;
}
}
Swift:
也需要擴(kuò)展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>] = []
//根據(jù)匹配范圍來(lái)用解碼后的字符串進(jìn)行相應(yīng)的替換
for match in resultArray {
//獲取數(shù)組元素中得到range
let range = match.range
//獲取原字符串中對(duì)應(yīng)的值
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)
//從后往前替換,否則會(huì)引起位置問(wèn)題
for dict in imageArray.reversed() {
resultStr.replaceCharacters(in: dict["range"] as! NSRange, with: dict["image"] as! String)
}
return resultStr
}
}
Swift中用到的擴(kuò)展:
extension String {
//Range轉(zhuǎn)換為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轉(zhuǎn)換為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
}
}
- 總結(jié)
坑:
某些Emoji例如??♀?,就是??+♀,采用變型表單包警,為那些可以顯示顏色和其他內(nèi)容的顯示器提供更多信息。
其中♀前后都有不可見(jiàn)字符底靠,用來(lái)表示♀是需要和??合并的。表示形式為:\u200d
♀\ufe0f
而我們?cè)诰幋aEmoji時(shí)特铝,將Emoji用<<>>括起來(lái)進(jìn)行發(fā)送暑中。
其中Swift語(yǔ)言編碼的String,會(huì)將>
這個(gè)符號(hào)和表情帶的\u200d
與\ufe0f
結(jié)合
>字符在String類(lèi)型下的不同
上圖就可以清楚的看出其中的不同鲫剿。
轉(zhuǎn)換成Unicode↓
字符 | 轉(zhuǎn)Unicode |
---|---|
??♀? | \ud83d\udc81\u200d\u2640\ufe0f |
?? | \ud83d\udc81 |
單個(gè)♀ | \u2640 |
用于表示Emoji更多信息的♀ | \u200d\u2640\ufe0f |
> | \u0026\u0067\u0074\u003b |
> | \u0026\u0067\u0074\u003b\u200d |
> | \u0026\u0067\u0074\u003b\ufe0f |
所以在實(shí)際使用時(shí)鳄逾,使用NSString來(lái)代替String。