系统表情
iOS系统表情与服务端的交互。
# 字符串(系统表情)绘制成图片
extension String {
func image() -> UIImage? {
let size = CGSize(width: 30, height: 35)
UIGraphicsBeginImageContextWithOptions(size, false, 0);
UIColor.white.set()
let rect = CGRect(origin: CGPoint(), size: size)
UIRectFill(CGRect(origin: CGPoint(), size: size))
(self as NSString).draw(in: rect, withAttributes: [NSFontAttributeName: UIFont.systemFont(ofSize: 30)])
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
# 系统表情16进制范围
let ranges = [0x1F601...0x1F64F, 0x2702...0x27B0]
let images = Array(ranges.flatten())
.map { UnicodeScalar($0) }
.map { Character($0) }
.map { String($0).image() }
# 判断是否包含系统表情
import UIKit
extension UnicodeScalar {
var isEmoji: Bool {
switch value {
case 0x1F600...0x1F64F, // Emoticons
0x1F300...0x1F5FF, // Misc Symbols and Pictographs
0x1F680...0x1F6FF, // Transport and Map
0x2600...0x26FF, // Misc symbols
0x2700...0x27BF, // Dingbats
0xFE00...0xFE0F, // Variation Selectors
0x1F900...0x1F9FF, // Supplemental Symbols and Pictographs
65024...65039, // Variation selector
8400...8447: // Combining Diacritical Marks for Symbols
return true
default: return false
}
}
var isZeroWidthJoiner: Bool {
return value == 8205
}
}
extension String {
var glyphCount: Int {
let richText = NSAttributedString(string: self)
let line = CTLineCreateWithAttributedString(richText)
return CTLineGetGlyphCount(line)
}
var isSingleEmoji: Bool {
return glyphCount == 1 && containsEmoji
}
var containsEmoji: Bool {
return unicodeScalars.contains { $0.isEmoji }
}
var containsOnlyEmoji: Bool {
return !isEmpty
&& !unicodeScalars.contains(where: {
!$0.isEmoji
&& !$0.isZeroWidthJoiner
})
}
// The next tricks are mostly to demonstrate how tricky it can be to determine emoji's
// If anyone has suggestions how to improve this, please let me know
var emojiString: String {
return emojiScalars.map { String($0) }.reduce("", +)
}
var emojis: [String] {
var scalars: [[UnicodeScalar]] = []
var currentScalarSet: [UnicodeScalar] = []
var previousScalar: UnicodeScalar?
for scalar in emojiScalars {
if let prev = previousScalar, !prev.isZeroWidthJoiner && !scalar.isZeroWidthJoiner {
scalars.append(currentScalarSet)
currentScalarSet = []
}
currentScalarSet.append(scalar)
previousScalar = scalar
}
scalars.append(currentScalarSet)
return scalars.map { $0.map{ String($0) } .reduce("", +) }
}
fileprivate var emojiScalars: [UnicodeScalar] {
var chars: [UnicodeScalar] = []
var previous: UnicodeScalar?
for cur in unicodeScalars {
if let previous = previous, previous.isZeroWidthJoiner && cur.isEmoji {
chars.append(previous)
chars.append(cur)
} else if cur.isEmoji {
chars.append(cur)
}
previous = cur
}
return chars
}
}
+ (BOOL)stringContainsEmoji:(NSString *)string
{
__block BOOL returnValue = NO;
[string enumerateSubstringsInRange:NSMakeRange(0, [string length])
options:NSStringEnumerationByComposedCharacterSequences
usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
const unichar hs = [substring characterAtIndex:0];
if (0xd800 <= hs && hs <= 0xdbff) {
if (substring.length > 1) {
const unichar ls = [substring characterAtIndex:1];
const int uc = ((hs - 0xd800) * 0x400) + (ls - 0xdc00) + 0x10000;
if (0x1d000 <= uc && uc <= 0x1f77f) {
returnValue = YES;
}
}
} else if (substring.length > 1) {
const unichar ls = [substring characterAtIndex:1];
if (ls == 0x20e3) {
returnValue = YES;
}
} else {
if (0x2100 <= hs && hs <= 0x27ff) {
returnValue = YES;
} else if (0x2B05 <= hs && hs <= 0x2b07) {
returnValue = YES;
} else if (0x2934 <= hs && hs <= 0x2935) {
returnValue = YES;
} else if (0x3297 <= hs && hs <= 0x3299) {
returnValue = YES;
} else if (hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50) {
returnValue = YES;
}
}
}];
return returnValue;
}
# 过滤字符串中系统表情
/// 过滤表情
///
/// - Returns: 去除表情以后的字符串
func rl_forbidEmoji() -> String {
guard let regex = try? NSRegularExpression(pattern: "[^\\u0020-\\u007E\\u00A0-\\u00BE\\u2E80-\\uA4CF\\uF900-\\uFAFF\\uFE30-\\uFE4F\\uFF00-\\uFFEF\\u0080-\\u009F\\u2000-\\u201f\r\n]", options: .caseInsensitive) else {
return self
}
return regex.stringByReplacingMatches(in: self, options: .reportCompletion, range: NSRange(location:0, length: self.count), withTemplate: "")
}