[ios] String in Character가 이모티콘인지 알아보세요?

문자열의 문자가 이모티콘인지 확인해야합니다.

예를 들어 다음과 같은 캐릭터가 있습니다.

let string = "?"
let character = Array(string)[0]

그 캐릭터가 이모티콘인지 알아 내야합니다.



답변

내가 우연히 발견 한 것은 문자, 유니 코드 스칼라 및 글리프의 차이입니다.

예를 들어 글리프 ?‍?‍?‍?는 7 개의 유니 코드 스칼라로 구성됩니다.

  • 4 개의 이모티콘 문자 : ????
  • 각 이모 지 사이에는 캐릭터 풀처럼 작동하는 특수 캐릭터가 있습니다. 자세한 내용 은 사양을 참조하십시오 .

또 다른 예, 글리프 ??는 2 개의 유니 코드 스칼라로 구성됩니다.

  • 일반 이모티콘 : ?
  • 피부톤 수정 자 : ?

마지막으로 글리프 1️⃣에는 세 개의 유니 코드 문자가 있습니다.

따라서 캐릭터를 렌더링 할 때 결과 글리프가 정말 중요합니다.

Swift 5.0 이상은이 과정을 훨씬 쉽게 만들어주고 우리가해야 할 추측을 없애줍니다. Unicode.Scalar의 새로운 Property유형은 우리가 다루는 것을 결정하는 데 도움이됩니다. 그러나 이러한 속성은 글리프 내의 다른 스칼라를 확인할 때만 의미가 있습니다. 이것이 우리를 돕기 위해 Character 클래스에 몇 가지 편리한 메서드를 추가하는 이유입니다.

자세한 내용 은 이것이 어떻게 작동하는지 설명하는 기사를 썼습니다 .

Swift 5.0의 경우 다음과 같은 결과가 나타납니다.

extension Character {
    /// A simple emoji is one scalar and presented to the user as an Emoji
    var isSimpleEmoji: Bool {
        guard let firstScalar = unicodeScalars.first else { return false }
        return firstScalar.properties.isEmoji && firstScalar.value > 0x238C
    }

    /// Checks if the scalars will be merged into an emoji
    var isCombinedIntoEmoji: Bool { unicodeScalars.count > 1 && unicodeScalars.first?.properties.isEmoji ?? false }

    var isEmoji: Bool { isSimpleEmoji || isCombinedIntoEmoji }
}

extension String {
    var isSingleEmoji: Bool { count == 1 && containsEmoji }

    var containsEmoji: Bool { contains { $0.isEmoji } }

    var containsOnlyEmoji: Bool { !isEmpty && !contains { !$0.isEmoji } }

    var emojiString: String { emojis.map { String($0) }.reduce("", +) }

    var emojis: [Character] { filter { $0.isEmoji } }

    var emojiScalars: [UnicodeScalar] { filter { $0.isEmoji }.flatMap { $0.unicodeScalars } }
}

다음과 같은 결과를 얻을 수 있습니다.

"A̛͚̖".containsEmoji // false
"3".containsEmoji // false
"A̛͚̖▶️".unicodeScalars // [65, 795, 858, 790, 9654, 65039]
"A̛͚̖▶️".emojiScalars // [9654, 65039]
"3️⃣".isSingleEmoji // true
"3️⃣".emojiScalars // [51, 65039, 8419]
"??".isSingleEmoji // true
"??‍♂️".isSingleEmoji // true
"??".isSingleEmoji // true
"⏰".isSingleEmoji // true
"?".isSingleEmoji // true
"?‍?‍?‍?".isSingleEmoji // true
"???????".isSingleEmoji // true
"???????".containsOnlyEmoji // true
"?‍?‍?‍?".containsOnlyEmoji // true
"Hello ?‍?‍?‍?".containsOnlyEmoji // false
"Hello ?‍?‍?‍?".containsEmoji // true
"? Héllo ?‍?‍?‍?".emojiString // "??‍?‍?‍?"
"?‍?‍?‍?".count // 1

"? Héllœ ?‍?‍?‍?".emojiScalars // [128107, 128104, 8205, 128105, 8205, 128103, 8205, 128103]
"? Héllœ ?‍?‍?‍?".emojis // ["?", "?‍?‍?‍?"]
"? Héllœ ?‍?‍?‍?".emojis.count // 2

"??‍?‍?‍??‍?‍?".isSingleEmoji // false
"??‍?‍?‍??‍?‍?".containsOnlyEmoji // true

이전 Swift 버전의 경우 이전 코드가 포함 된이 요점을 확인하십시오.


답변

이 작업을 수행 하는 가장 간단하고 깔끔하며 가장 빠른 방법은 다음과 같이 문자열의 각 문자에 대한 유니 코드 코드 포인트를 알려진 이모 지 및 딩뱃 범위와 비교하여 확인하는 것입니다.

extension String {

    var containsEmoji: Bool {
        for scalar in unicodeScalars {
            switch scalar.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
                 0x1F1E6...0x1F1FF: // Flags
                return true
            default:
                continue
            }
        }
        return false
    }

}


답변

extension String {
    func containsEmoji() -> Bool {
        for scalar in unicodeScalars {
            switch scalar.value {
            case 0x3030, 0x00AE, 0x00A9,// Special Characters
            0x1D000...0x1F77F,          // Emoticons
            0x2100...0x27BF,            // Misc symbols and Dingbats
            0xFE00...0xFE0F,            // Variation Selectors
            0x1F900...0x1F9FF:          // Supplemental Symbols and Pictographs
                return true
            default:
                continue
            }
        }
        return false
    }
}

이것은 업데이트 된 범위와 함께 내 수정입니다.


답변

스위프트 5.0

… 정확히 이것을 확인하는 새로운 방법을 도입했습니다!

당신은 String그것의 Scalars. 각 Scalar갖는다 Property지원 값isEmoji 가치를 가지고 있습니다!

실제로 Scalar가 Emoji modifier 이상인지 확인할 수도 있습니다. Apple의 문서를 확인하십시오 : https://developer.apple.com/documentation/swift/unicode/scalar/properties

Apple이 다음에 대해 다음과 같이 명시하고 있으므로 isEmojiPresentation대신에 확인하는 것이 좋습니다 .isEmojiisEmoji

이 속성은 기본적으로 이모티콘으로 렌더링되는 스칼라와 U + FE0F VARIATION SELECTOR-16이 뒤 따르는 경우 기본이 아닌 이모티콘 렌더링이있는 스칼라에 대해서도 true입니다. 여기에는 일반적으로 이모티콘으로 간주되지 않는 일부 스칼라가 포함됩니다.


이 방법은 실제로 Emoji를 모든 수정 자로 분할하지만 처리하기가 더 간단합니다. 그리고 Swift는 이제 수식어 (예 : ?‍?‍?‍?, ??‍?, ?)가있는 이모티콘을 1로 간주하므로 모든 종류의 작업을 수행 할 수 있습니다.

var string = "? test"

for scalar in string.unicodeScalars {
    let isEmoji = scalar.properties.isEmoji

    print("\(scalar.description) \(isEmoji)"))
}

// ? true
//   false
// t false
// e false
// s false
// t false

NSHipster 는 모든 이모티콘을 얻는 흥미로운 방법을 지적합니다.

import Foundation

var emoji = CharacterSet()

for codePoint in 0x0000...0x1F0000 {
    guard let scalarValue = Unicode.Scalar(codePoint) else {
        continue
    }

    // Implemented in Swift 5 (SE-0221)
    // https://github.com/apple/swift-evolution/blob/master/proposals/0221-character-properties.md
    if scalarValue.properties.isEmoji {
        emoji.insert(scalarValue)
    }
}


답변

Swift 5를 사용하면 이제 문자열에있는 각 문자의 유니 코드 속성을 검사 할 수 있습니다. 이것은 우리 isEmoji에게 각 문자에 대한 편리한 변수를 제공 합니다. 문제는 isEmoji0-9와 같이 2 바이트 이모티콘으로 변환 할 수있는 모든 문자에 대해 true를 반환한다는 것입니다.

변수를보고 isEmoji모호한 문자가 이모 지로 표시되는지 확인하기 위해 이모 지 수정자가 있는지 확인할 수 있습니다.

이 솔루션은 여기에서 제공되는 정규식 솔루션보다 훨씬 더 미래를 보장해야합니다.

extension String {
    func containsOnlyEmojis() -> Bool {
        if count == 0 {
            return false
        }
        for character in self {
            if !character.isEmoji {
                return false
            }
        }
        return true
    }

    func containsEmoji() -> Bool {
        for character in self {
            if character.isEmoji {
                return true
            }
        }
        return false
    }
}

extension Character {
    // An emoji can either be a 2 byte unicode character or a normal UTF8 character with an emoji modifier
    // appended as is the case with 3️⃣. 0x238C is the first instance of UTF16 emoji that requires no modifier.
    // `isEmoji` will evaluate to true for any character that can be turned into an emoji by adding a modifier
    // such as the digit "3". To avoid this we confirm that any character below 0x238C has an emoji modifier attached
    var isEmoji: Bool {
        guard let scalar = unicodeScalars.first else { return false }
        return scalar.properties.isEmoji && (scalar.value > 0x238C || unicodeScalars.count > 1)
    }
}

우리에게

"hey".containsEmoji() //false

"Hello World ?".containsEmoji() //true
"Hello World ?".containsOnlyEmojis() //false

"3".containsEmoji() //false
"3️⃣".containsEmoji() //true


답변

Swift 3 참고 :

표시 cnui_containsEmojiCharacters방법 중 어느 하나를 제거하거나 다른 동적 라이브러리로 이동되었다. _containsEmoji그래도 작동합니다.

let str: NSString = "hello?"

@objc protocol NSStringPrivate {
    func _containsEmoji() -> ObjCBool
}

let strPrivate = unsafeBitCast(str, to: NSStringPrivate.self)
strPrivate._containsEmoji() // true
str.value(forKey: "_containsEmoji") // 1


let swiftStr = "hello?"
(swiftStr as AnyObject).value(forKey: "_containsEmoji") // 1

Swift 2.x :

최근 NSString에 문자열에 이모티콘 문자가 포함되어 있는지 감지하는 기능을 제공 하는 비공개 API를 발견했습니다 .

let str: NSString = "hello?"

objc 프로토콜 및 unsafeBitCast:

@objc protocol NSStringPrivate {
    func cnui_containsEmojiCharacters() -> ObjCBool
    func _containsEmoji() -> ObjCBool
}

let strPrivate = unsafeBitCast(str, NSStringPrivate.self)
strPrivate.cnui_containsEmojiCharacters() // true
strPrivate._containsEmoji() // true

와 함께 valueForKey:

str.valueForKey("cnui_containsEmojiCharacters") // 1
str.valueForKey("_containsEmoji") // 1

순수한 Swift 문자열 AnyObject을 사용하면 valueForKey다음을 사용하기 전에 문자열을 캐스팅해야합니다 .

let str = "hello?"

(str as AnyObject).valueForKey("cnui_containsEmojiCharacters") // 1
(str as AnyObject).valueForKey("_containsEmoji") // 1

NSString 헤더 파일 에있는 메소드 .


답변

이 코드 예제 또는이 포드를 사용할 수 있습니다 .

Swift에서 사용하려면 카테고리를 YourProject_Bridging_Header

#import "NSString+EMOEmoji.h"

그런 다음 문자열에있는 모든 이모티콘의 범위를 확인할 수 있습니다.

let example: NSString = "string?‍?‍?‍?with?emojis✊?" //string with emojis

let containsEmoji: Bool = example.emo_containsEmoji()

    print(containsEmoji)

// Output: ["true"]

위의 코드로 작은 예제 프로젝트를 만들었습니다.