文字列の文字が絵文字かどうか調べますか?


92

文字列内の文字が絵文字であるかどうかを確認する必要があります。

たとえば、私はこのキャラクターを持っています:

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

その文字が絵文字かどうかを確認する必要があります。


私は興味があります:なぜあなたはその情報が必要なのですか?
マーティンR

@EricD。:複数のUTF-8コードポイント(例: "€" = E2 82 AC)または複数のUTF-16コードポイント(例: "𝄞" = D834 DD1E)を使用するUnicode文字が多数あります。
マーティンR

このobj-cバージョンのコードstackoverflow.com/questions/19886642/…
Ashish Kakkad 2015年

文字列には、それらを使用するための好ましい方法であるインデックスがあります。あなたは(というか、書記素クラスタ)特定の文字をでき得るには:let character = string[string.index(after: string.startIndex)]または let secondCharacter = string[string.index(string.startIndex, offsetBy: 1)]
ポールB

回答:


239

私が偶然見つけたのは、文字、Unicodeスカラー、およびグリフの違いです。

たとえば、グリフ👨‍👨‍👧‍👧は7つのUnicodeスカラーで構成されています。

  • 4つの絵文字:👨👩👧👧
  • 各絵文字の間には、文字のりのように機能する特殊文字があります。詳細については、仕様を参照してください

別の例として、グリフ👌🏿は2つのUnicodeスカラーで構成されています。

  • 通常の絵文字:👌
  • 肌のトーンモディファイア:🏿

最後の1つは、グリフ1️⃣に3つのUnicode文字が含まれています。

したがって、文字をレンダリングするとき、結果のグリフは本当に重要です。

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バージョンについては、私の古いコードを含むこの要点を確認してください。


6
これは、ここで断然最良かつ最も正しい答えです。ありがとうございました!小さな注意点として、例がコードと一致していません(スニペットでcontainsOnlyEmokiの名前をcontainsEmojiに変更しました-より正確であるため、テストでは、混合文字を含む文字列に対してtrueが返されました)。
ティム・ブル

3
私の悪い、私はいくつかのコードを変更しました、私が台無しにしたと思います。例を更新しました
Kevin R

2
@Andrew:確かに、これを示すために例に別のメソッドを追加しました:)。
ケビンR

2
@Andrewこれは本当に厄介になるところです。その方法の例を追加しました。問題は、CoreTextが文字をチェックするだけでグリフをレンダリングする方法を知っていると想定していることです。よりクリーンな方法の提案があれば教えてください。
ケビンR

3
@Andrewそれを指摘してくれてありがとう、私はcontainsOnlyEmojiチェックの方法を変えました。また、例をSwift3.0に更新しました。
ケビンR

51

これを実現するための最も簡単でクリーンで迅速な方法は、次のように、文字列内の各文字のUnicodeコードポイントを既知の絵文字と絵文字の範囲と照合することです。

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
    }

}

9
このようなコード例は、サードパーティのライブラリ依存関係を含めることを提案するよりもはるかに優れています。Shardulの答えは、従うべき賢明なアドバイスではありません。常に独自のコードを記述してください。
thefaj 2016年

これは素晴らしいことです。事件が何に関係するかコメントしてくれてありがとう
Shawn Throop 2016

2
多くのあなたのコードのように、私はここの答えそれを実装しました。私が気づいた事は、たとえば、彼らはあなたが記載されているカテゴリの一部ではないかもしれないので、それはいくつかの絵文字を逃すことに、このいずれかになります。ロボットの顔絵文字🤖
キュー

1
@Tel私はそれが範囲になると思います0x1F900...0x1F9FF(ウィキペディアによる)。すべての範囲を絵文字と見なす必要があるかどうかはわかりません。
Frizlab 2016

11

Swift 5.0

…これを正確にチェックする新しい方法を導入しました!

あなたはStringそのにあなたを壊さなければなりませんScalars。それぞれScalarProperty値をサポートするisEmoji値があります!

実際には、スカラーが絵文字修飾子以上であるかどうかを確認することもできます。Appleのドキュメントをチェックしてください:https//developer.apple.com/documentation/swift/unicode/scalar/properties

Appleは次のように述べているので、のisEmojiPresentation代わりにチェックすることを検討することをお勧めしisEmojiますisEmoji

このプロパティは、デフォルトで絵文字としてレンダリングされるスカラー、およびU + FE0F VARIATIONSELECTOR-16が後に続く場合にデフォルト以外の絵文字レンダリングを持つスカラーにも当てはまります。これには、通常は絵文字とは見なされないスカラーが含まれます。


この方法では、実際には絵文字をすべての修飾子に分割しますが、処理ははるかに簡単です。また、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)
    }
}

1
素晴らしい答え、ありがとう。それの価値があなたの分のSDKは10.2文字列が唯一の私はそれがこれらのプロパティのいずれかを持っていたかどうかを確認しなければならなかった絵文字を作ったかどうかを確認するために、またスウィフト5のこの部分を使用しなければならないことに言及:scalar.properties.isEmoji scalar.properties.isEmojiPresentation scalar.properties.isEmojiModifier scalar.properties.isEmojiModifierBase scalar.properties.isJoinControl scalar.properties.isVariationSelector
A Springham

6
0〜9の整数は絵文字と見なされることに注意してください。だから、"6".unicodeScalars.first!.properties.isEmojiとして評価されますtrue
Miniroo

1
そこのような他の文字がある#*、それはまたのためにtrueを返しますisEmojiチェック。isEmojiPresentation少なくとも、、、および英語と米国のキーボードで試すことができる他の記号falseに対して0...9#、より適切に機能するよう*です。誰かがそれについてより多くの経験を持っていて、それが入力検証のために信頼できるかどうか知っていますか?
1月

8
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
    }
}

これは私の修正であり、範囲が更新されています。


7

Swift 5を使用すると、文字列内の各文字のUnicodeプロパティを検査できるようになりました。これによりisEmoji、各文字に便利な変数が与えられます。問題はisEmoji、0〜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

1
そして、何よりだことはありCharacter("3️⃣").isEmoji // trueながらCharacter("3").isEmoji // false
ポールB

4

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

スイフト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ヘッダーファイルにあるメソッド。


これは私が探しているものです、ありがとうJAL

これはAppleによって拒否されますか?
Andrey Chernukha 2016

@AndreyChernukha常にリスクがありますが、私はまだ拒否を経験していません。
JAL

プライベートAPIは絶対に使用しないでください。せいぜい、傷は明日だけ来るでしょう。または来月。
xaphod 2017年

3

このコードまたはこのポッドを使用できます。

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"]

上記のコードを使用して、小さなサンプルプロジェクトを作成しました。


3

将来の証拠:キャラクターのピクセルを手動でチェックします。新しい絵文字が追加されると、他のソリューションは壊れます(そして壊れます)。

注:これはObjective-Cです(Swiftに変換できます)

何年にもわたって、これらの絵文字検出ソリューションは、Appleが新しい方法で新しい絵文字を追加するにつれて壊れ続けています(追加の文字で文字をプリカーシングすることによって構築された肌色の絵文字など)。

私はついに故障し、現在のすべての絵文字で機能し、将来のすべての絵文字で機能する次のメソッドを作成しました。

このソリューションは、文字と黒い背景を持つUILabelを作成します。次に、CGはラベルのスナップショットを取得し、スナップショット内のすべてのピクセルをスキャンして、黒一色以外のピクセルを探します。黒の背景を追加する理由は、サブピクセルレンダリングによる偽色の問題を回避するためです。

このソリューションは私のデバイスで非常に高速に実行され、1秒間に数百文字をチェックできますが、これはCoreGraphicsソリューションであり、通常のテキストメソッドのように頻繁に使用しないでください。グラフィックス処理はデータ量が多いため、一度に数千文字をチェックすると、顕著な遅延が発生する可能性があります。

-(BOOL)isEmoji:(NSString *)character {
    
    UILabel *characterRender = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
    characterRender.text = character;
    characterRender.font = [UIFont fontWithName:@"AppleColorEmoji" size:12.0f];//Note: Size 12 font is likely not crucial for this and the detector will probably still work at an even smaller font size, so if you needed to speed this checker up for serious performance you may test lowering this to a font size like 6.0
    characterRender.backgroundColor = [UIColor blackColor];//needed to remove subpixel rendering colors
    [characterRender sizeToFit];
    
    CGRect rect = [characterRender bounds];
    UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
    CGContextRef contextSnap = UIGraphicsGetCurrentContext();
    [characterRender.layer renderInContext:contextSnap];
    UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    CGImageRef imageRef = [capturedImage CGImage];
    NSUInteger width = CGImageGetWidth(imageRef);
    NSUInteger height = CGImageGetHeight(imageRef);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char));
    NSUInteger bytesPerPixel = 4;//Note: Alpha Channel not really needed, if you need to speed this up for serious performance you can refactor this pixel scanner to just RGB
    NSUInteger bytesPerRow = bytesPerPixel * width;
    NSUInteger bitsPerComponent = 8;
    CGContextRef context = CGBitmapContextCreate(rawData, width, height,
                                                 bitsPerComponent, bytesPerRow, colorSpace,
                                                 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
    CGContextRelease(context);
    
    BOOL colorPixelFound = NO;
    
    int x = 0;
    int y = 0;
    while (y < height && !colorPixelFound) {
        while (x < width && !colorPixelFound) {
            
            NSUInteger byteIndex = (bytesPerRow * y) + x * bytesPerPixel;
            
            CGFloat red = (CGFloat)rawData[byteIndex];
            CGFloat green = (CGFloat)rawData[byteIndex+1];
            CGFloat blue = (CGFloat)rawData[byteIndex+2];
            
            CGFloat h, s, b, a;
            UIColor *c = [UIColor colorWithRed:red green:green blue:blue alpha:1.0f];
            [c getHue:&h saturation:&s brightness:&b alpha:&a];//Note: I wrote this method years ago, can't remember why I check HSB instead of just checking r,g,b==0; Upon further review this step might not be needed, but I haven't tested to confirm yet. 
            
            b /= 255.0f;
            
            if (b > 0) {
                colorPixelFound = YES;
            }
            
            x++;
        }
        x=0;
        y++;
    }
    
    return colorPixelFound;
    
}

5
私はあなたの考えが好きです!;)-箱から出して!
ラモン

なぜあなたは私たちにこれをしているのですか?#apple#unicodestandard😱🤔🤪🙈😈🤕💩
d4Rk19年

しばらくこれを見ていませんが、UIColorに変換してからhsbに変換する必要があるのではないかと思います。r、g、b all == 0を確認できるようです。誰かが私に
アルバートレンショー

私はこの解決策が好きですが、ℹのような文字で壊れませんか?
Juan Carlos OspinaGonzalez19年

1
@JuanCarlosOspinaGonzalezいいえ、白いiが付いた青いボックスとしてレンダリングされる絵文字です。UILabelがフォントを強制する必要があるというのは良い点ですが、これをAppleColorEmojiフェイルセーフとして追加しますが、Appleはとにかくデフォルトにするだろうと思います
AlbertRenshaw19年

2

Swift 3.0.2の場合、次の答えが最も簡単です。

class func stringContainsEmoji (string : NSString) -> Bool
{
    var returnValue: Bool = false

    string.enumerateSubstrings(in: NSMakeRange(0, (string as NSString).length), options: NSString.EnumerationOptions.byComposedCharacterSequences) { (substring, substringRange, enclosingRange, stop) -> () in

        let objCString:NSString = NSString(string:substring!)
        let hs: unichar = objCString.character(at: 0)
        if 0xd800 <= hs && hs <= 0xdbff
        {
            if objCString.length > 1
            {
                let ls: unichar = objCString.character(at: 1)
                let step1: Int = Int((hs - 0xd800) * 0x400)
                let step2: Int = Int(ls - 0xdc00)
                let uc: Int = Int(step1 + step2 + 0x10000)

                if 0x1d000 <= uc && uc <= 0x1f77f
                {
                    returnValue = true
                }
            }
        }
        else if objCString.length > 1
        {
            let ls: unichar = objCString.character(at: 1)
            if ls == 0x20e3
            {
                returnValue = true
            }
        }
        else
        {
            if 0x2100 <= hs && hs <= 0x27ff
            {
                returnValue = true
            }
            else if 0x2b05 <= hs && hs <= 0x2b07
            {
                returnValue = true
            }
            else if 0x2934 <= hs && hs <= 0x2935
            {
                returnValue = true
            }
            else if 0x3297 <= hs && hs <= 0x3299
            {
                returnValue = true
            }
            else if hs == 0xa9 || hs == 0xae || hs == 0x303d || hs == 0x3030 || hs == 0x2b55 || hs == 0x2b1c || hs == 0x2b1b || hs == 0x2b50
            {
                returnValue = true
            }
        }
    }

    return returnValue;
}

2

私の前に書いたものとまったく同じ答えですが、絵文字スカラーの更新されたセットがあります。

extension String {
    func isContainEmoji() -> Bool {
        let isContain = unicodeScalars.first(where: { $0.isEmoji }) != nil
        return isContain
    }
}


extension UnicodeScalar {

    var isEmoji: Bool {
        switch value {
        case 0x1F600...0x1F64F,
             0x1F300...0x1F5FF,
             0x1F680...0x1F6FF,
             0x1F1E6...0x1F1FF,
             0x2600...0x26FF,
             0x2700...0x27BF,
             0xFE00...0xFE0F,
             0x1F900...0x1F9FF,
             65024...65039,
             8400...8447,
             9100...9300,
             127000...127600:
            return true
        default:
            return false
        }
    }

}


1

上記のタスクには優れた解決策があります。ただし、UnicodeスカラーのUnicode.Scalar.Propertiesを確認することは、単一の文字に適しています。そして、文字列に対して十分な柔軟性がありません。

代わりに正規表現を使用できます—より普遍的なアプローチです。それがどのように機能するかについての詳細な説明が以下にあります。そして、ここに解決策があります。

ソリューション

Swiftでは、次のような計算されたプロパティを持つ拡張機能を使用して、文字列が単一の絵文字であるかどうかを確認できます。

extension String {

    var isSingleEmoji : Bool {
        if self.count == 1 {
            let emodjiGlyphPattern = "\\p{RI}{2}|(\\p{Emoji}(\\p{EMod}|\\x{FE0F}\\x{20E3}?|[\\x{E0020}-\\x{E007E}]+\\x{E007F})|[\\p{Emoji}&&\\p{Other_symbol}])(\\x{200D}(\\p{Emoji}(\\p{EMod}|\\x{FE0F}\\x{20E3}?|[\\x{E0020}-\\x{E007E}]+\\x{E007F})|[\\p{Emoji}&&\\p{Other_symbol}]))*"

            let fullRange = NSRange(location: 0, length: self.utf16.count)
            if let regex = try? NSRegularExpression(pattern: emodjiGlyphPattern, options: .caseInsensitive) {
                let regMatches = regex.matches(in: self, options: NSRegularExpression.MatchingOptions(), range: fullRange)
                if regMatches.count > 0 {
                    // if any range found — it means, that that single character is emoji
                    return true
                }
            }
        }
        return false
    }

}

仕組み(詳細)

単一の絵文字(グリフ)は、さまざまな記号、シーケンス、およびそれらの組み合わせで再現できます。 Unicode仕様では、いくつかの可能な絵文字表現が定義されています。

1文字の絵文字

1つのUnicodeスカラーによって再現された絵文字。

Unicodeは、絵文字を次のように定義しています。

emoji_character := \p{Emoji}

しかし、必ずしもそのようなキャラクターが絵文字として描かれることを意味するわけではありません。通常の数字記号「1」は、テキストとして描画される場合もありますが、絵文字プロパティがtrueです。そして、そのような記号のリストがあります:#、©、4など。

「Emoji_Presentation」をチェックするために追加のプロパティを使用できることを考える必要があります。しかし、それはこのようには機能しません。🏟や🛍のような絵文字があり、プロパティEmoji_Presentation = falseがあります。

キャラクターがデフォルトで絵文字として描画されていることを確認するには、そのカテゴリを確認する必要があります。「Other_symbol」である必要があります。

したがって、実際には、単一文字の絵文字の正規表現は次のように定義する必要があります。

emoji_character := \p{Emoji}&&\p{Other_symbol}

絵文字のプレゼンテーションシーケンス

通常、テキストまたは絵文字として描画できる文字。外観は、プレゼンテーションの種類を示す特別な次の記号であるプレゼンテーションセレクターによって異なります。\ x {FE0E}はテキスト表現を定義します。\ x {FE0F}は絵文字表現を定義します。

このような記号のリストは[ここ](
 https://unicode.org/Public/emoji/12.1/emoji-variation-sequences.txt)にあります。

Unicodeは、次のようなプレゼンテーションシーケンスを定義します。

emoji_presentation_sequence := emoji_character emoji_presentation_selector

そのための正規表現シーケンス:

emoji_presentation_sequence := \p{Emoji} \x{FE0F}

絵文字キーキャップシーケンス

シーケンスはプレゼンテーションシーケンスと非常によく似ていますが、最後に追加のスカラーがあります:\ x {20E3}。それに使用される可能性のあるベーススカラーの範囲はかなり狭いです:0-9#* —そしてそれだけです。例:1️⃣、8️⃣、*️⃣。

Unicodeは、次のようにキーキャップシーケンスを定義します。

emoji_keycap_sequence := [0-9#*] \x{FE0F 20E3}

その正規表現:

emoji_keycap_sequence := \p{Emoji} \x{FE0F} \x{FE0F}

絵文字修飾子シーケンス

一部の絵文字は、肌の色のように外観を変更できます。たとえば、絵文字🧑は異なる場合があります:🧑🧑🏻🧑🏼🧑🏽🧑🏾🧑🏿。この場合「Emoji_Modifier_Base」と呼ばれる絵文字を定義するには、後続の「Emoji_Modifier」を使用できます。

一般に、このようなシーケンスは次のようになります。

emoji_modifier_sequence := emoji_modifier_base emoji_modifier

それを検出するために、正規表現シーケンスを検索できます。

emoji_modifier_sequence := \p{Emoji} \p{EMod}

絵文字フラグシーケンス

フラグは、特定の構造を持つ絵文字です。各フラグは、2つの「Regional_Indicator」シンボルで表されます。

Unicodeはそれらを次のように定義します。

emoji_flag_sequence := regional_indicator regional_indicator

たとえば、ウクライナの旗🇺🇦は実際には2つのスカラーで表されます:\ u {0001F1FA \ u {0001F1E6}

その正規表現:

emoji_flag_sequence := \p{RI}{2}

絵文字タグシーケンス(ETS)

いわゆるtag_baseを使用するシーケンス。その後に、シンボルの範囲\ x {E0020}-\ x {E007E}で構成され、tag_endマーク\ x {E007F}で終了するカスタムタグ仕様が続きます。

Unicodeはそれを次のように定義します:

emoji_tag_sequence := tag_base tag_spec tag_end
tag_base           := emoji_character
                    | emoji_modifier_sequence
                    | emoji_presentation_sequence
tag_spec           := [\x{E0020}-\x{E007E}]+
tag_end            := \x{E007F}

奇妙なことに、Unicodeでは、ED-14aのemoji_modifier_sequenceまたはemoji_presentation_sequenceに基づいてタグを付けることができます。しかし同時に、同じドキュメントで提供されている正規表現では、単一の絵文字のみに基づいてシーケンスをチェックしているようです。

Unicode 12.1絵文字リストでは、そのような絵文字は3つしか定義されていません。それらはすべて英国の国の旗です:イングランド🏴י§ そして、それらはすべて単一の絵文字に基づいています。したがって、そのようなシーケンスのみをチェックすることをお勧めします。

正規表現:

\p{Emoji} [\x{E0020}-\x{E007E}]+ \x{E007F}

絵文字ゼロ幅接合子シーケンス(ZWJシーケンス)

ゼロ幅接合子はスカラー\ x {200D}です。その助けを借りて、すでにそれ自体が絵文字であるいくつかのキャラクターを新しいものに組み合わせることができます。

たとえば、「父、息子、娘のいる家族」の絵文字👨‍👧‍👦は、父👨、娘👧、息子👦の絵文字をZWJシンボルで接着して再現しています。

単一の絵文字、プレゼンテーション、修飾子のシーケンスである要素をくっつけることができます。

このようなシーケンスの正規表現は、一般的に次のようになります。

emoji_zwj_sequence := emoji_zwj_element (\x{200d} emoji_zwj_element )+

それらすべての正規表現

上記のすべての絵文字表現は、単一の正規表現で記述できます。

\p{RI}{2}
| ( \p{Emoji} 
    ( \p{EMod} 
    | \x{FE0F}\x{20E3}? 
    | [\x{E0020}-\x{E007E}]+\x{E007F} 
    ) 
  | 
[\p{Emoji}&&\p{Other_symbol}] 
  )
  ( \x{200D}
    ( \p{Emoji} 
      ( \p{EMod} 
      | \x{FE0F}\x{20E3}? 
      | [\x{E0020}-\x{E007E}]+\x{E007F} 
      ) 
    | [\p{Emoji}&&\p{Other_symbol}] 
    ) 
  )*

-1

私は同じ問題を抱えていて、拡張機能を作成することにStringなりましたCharacter

コードは長すぎて投稿できません。実際には、すべての絵文字(公式のUnicodeリストv5.0から)がリストされているCharacterSetため、次の場所にあります。

https://github.com/piterwilson/StringEmoji

定数

emojiCharacterSet:CharacterSetをしましょう

既知のすべての絵文字を含む文字セット(公式のUnicodeリスト5.0 http://unicode.org/emoji/charts-5.0/emoji-list.htmlで説明されています)

ストリング

var isEmoji:Bool {get}

Stringインスタンスが既知の単一の絵文字を表すかどうか

print("".isEmoji) // false
print("😁".isEmoji) // true
print("😁😜".isEmoji) // false (String is not a single Emoji)
var containsEmoji:Bool {get}

Stringインスタンスに既知の絵文字が含まれているかどうか

print("".containsEmoji) // false
print("😁".containsEmoji) // true
print("😁😜".containsEmoji) // true
var unicodeName:String {get}

文字列のコピーにkCFStringTransformToUnicodeName-CFStringTransformを適用します

print("á".unicodeName) // \N{LATIN SMALL LETTER A WITH ACUTE}
print("😜".unicodeName) // "\N{FACE WITH STUCK-OUT TONGUE AND WINKING EYE}"
var niceUnicodeName:String {get}

戻り値の結果kCFStringTransformToUnicodeName-CFStringTransformを持つ\N{接頭辞と}接尾辞を削除します

print("á".unicodeName) // LATIN SMALL LETTER A WITH ACUTE
print("😜".unicodeName) // FACE WITH STUCK-OUT TONGUE AND WINKING EYE

キャラクター

var isEmoji:Bool {get}

Characterインスタンスが既知の絵文字を表すかどうか

print("".isEmoji) // false
print("😁".isEmoji) // true
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.