ios - স্ট্রিংয়ে চরিত্রটি ইমোজি হয় কিনা তা সন্ধান করুন?



string swift (9)

ভবিষ্যতের প্রমাণ: ম্যানুয়ালি চরিত্রটির পিক্সেল পরীক্ষা করুন; নতুন ইমোজিগুলি যুক্ত হওয়ার সাথে সাথে অন্যান্য সমাধানগুলি ভেঙ্গে যাবে (এবং ভেঙে গেছে)।

দ্রষ্টব্য: এটি উদ্দেশ্য-সি (সুইফটে রূপান্তরিত হতে পারে)

বছরের পর বছর ধরে এই ইমোজি সনাক্তকরণের সমাধানগুলি ভাঙতে থাকে কারণ অ্যাপল নতুন ইমোজিস ডাব্লু / নতুন পদ্ধতি যুক্ত করে (যেমন স্কিন-টোনড ইমোজিগুলি একটি অতিরিক্ত চরিত্রের সাথে একটি অক্ষরের প্রাক-অভিশাপ দ্বারা নির্মিত) ইত্যাদি।

আমি অবশেষে ভেঙেছি এবং কেবলমাত্র নিম্নলিখিত পদ্ধতিটি লিখেছি যা সমস্ত বর্তমান ইমোজিদের জন্য কাজ করে এবং ভবিষ্যতের সমস্ত ইমোজিদের জন্য কাজ করা উচিত।

সমাধান অক্ষর এবং একটি কালো পটভূমি সহ একটি ইউআইএলবেল তৈরি করে। সিজি তার পরে লেবেলের একটি স্ন্যাপশট নেয় এবং আমি কোনও সলিড-কালো পিক্সেলের জন্য স্ন্যাপশটে সমস্ত পিক্সেল স্ক্যান করি। আমি কালো পটভূমি যুক্ত করার কারণ হ'ল সাবপিক্সেল রেন্ডারিংয়ের কারণে মিথ্যা-বর্ণের সমস্যাগুলি এড়ানো

সমাধানটি আমার ডিভাইসে খুব দ্রুত সঞ্চালিত হয়, আমি কয়েক সেকেন্ডে কয়েক হাজার অক্ষর চেক করতে পারি, তবে এটি লক্ষ্য করা উচিত যে এটি একটি কোরগ্রাফিক্স সমাধান এবং আপনার নিয়মিত পাঠ্য পদ্ধতির মতো ভারী ব্যবহার করা উচিত নয়। গ্রাফিক্স প্রসেসিং ডেটা ভারী তাই একসাথে কয়েক হাজার অক্ষর পরীক্ষা করা লক্ষণীয় পিছনে হতে পারে।

-(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;

}

স্ট্রিংয়ের একটি চরিত্র ইমোজি কিনা তা আমার খুঁজে বের করতে হবে।

উদাহরণস্বরূপ, আমার এই চরিত্রটি রয়েছে:

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

সেই চরিত্রটি ইমোজি কিনা তা আমাকে খুঁজে বের করতে হবে।


সুইফ্ট 5.0

… ঠিক এই চেক করার একটি নতুন উপায় চালু!

আপনার String এর Scalars । প্রতিটি isEmoji একটি Property মান রয়েছে যা isEmoji মানটিকে সমর্থন করে!

আসলে আপনি এমনকি স্কেলারটি কোনও ইমোজি সংশোধক বা আরও বেশি কিনা তাও পরীক্ষা করতে পারেন। অ্যাপলের ডকুমেন্টেশন দেখুন: Property

আপনি isEmojiPresentation পরিবর্তে isEmojiPresentation পরীক্ষা করার বিষয়টি বিবেচনা করতে পারেন, কারণ অ্যাপল isEmoji জন্য নিম্নলিখিতটি isEmoji :

এই সম্পত্তিটি স্কেলারের ক্ষেত্রে সত্য যা ডিফল্টরূপে ইমোজি হিসাবে রেন্ডার করা হয় এবং স্কেলারের ক্ষেত্রেও যখন ইউ + FE0F ভেরিয়েশন সিলেক্টর -16 অনুসরণ করে অ-ডিফল্ট ইমোজি রেন্ডারিং থাকে। এর মধ্যে এমন কিছু স্কেলার রয়েছে যা সাধারণত ইমোজি হিসাবে বিবেচিত হয় না।

এই পদ্ধতিটি ইমোজিগুলিকে সমস্ত সংশোধকগুলিতে ভাগ করে দেয় তবে এটি পরিচালনা করা সহজ। এবং সুইফট এখন ইমোজিদের সংশোধনকারী হিসাবে গণনা করেছে (যেমন: 👨‍👩‍👧‍👦, 👨🏻‍💻, 🏴) আপনি 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)
    }
}

আপনি NSString-RemoveEmoji মতো ব্যবহার করতে পারেন:

"hey".containsEmoji() //false

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

"😎".containsEmoji() //true
"😎".containsOnlyEmojis() //true

আপনি এই কোড example বা এই pod ব্যবহার করতে পারেন।

এটি YourProject_Bridging_Header ব্যবহার করতে, YourProject_Bridging_Header আপনার 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"]

আমি উপরের কোড সহ একটি ছোট উদাহরণ প্রকল্প তৈরি করেছি।


আমার একই সমস্যা ছিল এবং String এবং Character এক্সটেনশানগুলি শেষ করেছিলাম।

কোডটি পোস্ট করার জন্য অনেক দীর্ঘ কারণ এটি একটি চরিত্রসীটে প্রকৃতপক্ষে সমস্ত ইমোজিদের (অফিসিয়াল ইউনিকোড তালিকা v5.0 থেকে) তালিকাভুক্ত করে আপনি এটি এখানে পেতে পারেন:

https://github.com/piterwilson/StringEmoji

ধ্রুবক

ইমোজিচার্যাক্টসেট: ক্যারেক্টারসেট দিন

সমস্ত পরিচিত ইমোজি সমন্বিত অক্ষর সেট (অফিসিয়াল ইউনিকোড তালিকায় বর্ণিত 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)
ভের রয়েছে ইমোজি: বুল {পেতে}

String ইনস্ট্যান্সে একটি পরিচিত ইমোজি চরিত্র রয়েছে কিনা

print("".containsEmoji) // false
print("😁".containsEmoji) // true
print("😁😜".containsEmoji) // true
var unicodeName: স্ট্রিং {get}

kCFStringTransformToUnicodeName একটি kCFStringTransformToUnicodeName - CFStringTransform প্রয়োগ করে

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

kCFStringTransformToUnicodeName \N{ উপসর্গ এবং } প্রত্যয় মুছে ফেলা একটি kCFStringTransformToUnicodeName - CFStringTransform kCFStringTransformToUnicodeName ফলাফল প্রদান করে

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

আমি যা হোঁচট খেয়েছি তা হ'ল অক্ষর, ইউনিকোড স্কেলার এবং গ্লাইফের মধ্যে পার্থক্য।

উদাহরণস্বরূপ, গ্লাইফ 👨‍👨‍👧‍👧 7 টি ইউনিকোড স্কেলার নিয়ে গঠিত:

অন্য একটি উদাহরণ, গ্লাইফ 2 টি ইউনিকোড স্কেলার নিয়ে গঠিত:

  • নিয়মিত ইমোজি: 👌
  • একটি ত্বকের স্বন সংশোধক: 🏿

সুতরাং চরিত্রগুলি রেন্ডার করার সময়, ফলস্বরূপ গ্লাইফগুলি সত্যই গুরুত্বপূর্ণ।

আমি যে সন্ধান করছিলাম তা হ'ল একটি স্ট্রিং ঠিক এবং কেবল একটি ইমোজি কিনা তা সনাক্ত করার একটি উপায়। সুতরাং আমি এটিকে সাধারণ পাঠ্যের চেয়ে বড় আকারে রেন্ডার করতে পারি (যেমন বার্তাগুলি আইওএস 10 তে করেন এবং হোয়াটসঅ্যাপ আজকাল করেন)। উপরে বর্ণিত হিসাবে, চরিত্র গণনা সত্যিই কোন কাজে আসে না। ('আঠালো চরিত্র' কে ইমোজি হিসাবে বিবেচনা করা হয় না)।

আপনি যা করতে পারেন তা হ'ল গিলেফগুলিতে স্ট্রিংটি ভাঙ্গতে এবং সেগুলি গণনা করতে সহায়তা করার জন্য কোরটেক্সট ব্যবহার করুন। তদুপরি, আমি আর্নল্ড এবং সেবাস্তিয়ান লোপেজ প্রস্তাবিত UnicodeScalar পৃথক প্রসারণে UnicodeScalar

এটি আপনাকে নিম্নলিখিত ফলাফল সহ ছেড়ে দেয়:

import Foundation

extension UnicodeScalar {
    /// Note: This method is part of Swift 5, so you can omit this. 
    /// See: https://developer.apple.com/documentation/swift/unicode/scalar
    var isEmoji: Bool {
        switch value {
        case 0x1F600...0x1F64F, // Emoticons
             0x1F300...0x1F5FF, // Misc Symbols and Pictographs
             0x1F680...0x1F6FF, // Transport and Map
             0x1F1E6...0x1F1FF, // Regional country flags
             0x2600...0x26FF, // Misc symbols
             0x2700...0x27BF, // Dingbats
             0xE0020...0xE007F, // Tags
             0xFE00...0xFE0F, // Variation Selectors
             0x1F900...0x1F9FF, // Supplemental Symbols and Pictographs
             0x1F018...0x1F270, // Various asian characters
             0x238C...0x2454, // Misc items
             0x20D0...0x20FF: // Combining Diacritical Marks for Symbols
            return true

        default: return false
        }
    }

    var isZeroWidthJoiner: Bool {
        return value == 8205
    }
}

extension String {
    // Not needed anymore in swift 4.2 and later, using `.count` will give you the correct result
    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
    }
}

যা আপনাকে নিম্নলিখিত ফলাফলগুলি দেবে:

"👌🏿".isSingleEmoji // true
"🙎🏼‍♂️".isSingleEmoji // true
"👨‍👩‍👧‍👧".isSingleEmoji // true
"👨‍👩‍👧‍👧".containsOnlyEmoji // true
"Hello 👨‍👩‍👧‍👧".containsOnlyEmoji // false
"Hello 👨‍👩‍👧‍👧".containsEmoji // true
"👫 Héllo 👨‍👩‍👧‍👧".emojiString // "👫👨‍👩‍👧‍👧"
"👨‍👩‍👧‍👧".glyphCount // 1
"👨‍👩‍👧‍👧".characters.count // 4, Will return '1' in Swift 4.2 so previous method not needed anymore
"👨‍👩‍👧‍👧".count // 4, Will return '1' in Swift 4.2 so previous method not needed anymore

"👫 Héllœ 👨‍👩‍👧‍👧".emojiScalars // [128107, 128104, 8205, 128105, 8205, 128103, 8205, 128103]
"👫 Héllœ 👨‍👩‍👧‍👧".emojis // ["👫", "👨‍👩‍👧‍👧"]

"👫👨‍👩‍👧‍👧👨‍👨‍👦".isSingleEmoji // false
"👫👨‍👩‍👧‍👧👨‍👨‍👦".containsOnlyEmoji // true
"👫👨‍👩‍👧‍👧👨‍👨‍👦".glyphCount // 3
"👫👨‍👩‍👧‍👧👨‍👨‍👦".characters.count // 8, Will return '3' in Swift 4.2 so previous method not needed anymore

সুইফট 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 একটি ব্যক্তিগত এপিআই আবিষ্কার করেছি যা স্ট্রিংয়ে ইমোজি অক্ষর রয়েছে কিনা তা সনাক্ত করার জন্য কার্যকারিতা প্রকাশ করে:

let str: NSString = "hello😊"

একটি অবজেক্ট প্রোটোকল এবং 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

খাঁটি সুইফ্ট স্ট্রিংয়ের সাথে, AnyObject ব্যবহার করার আগে আপনাকে স্ট্রিংটিকে AnyObject হিসাবে কাস্ট করতে হবে:

let str = "hello😊"

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

এনএসএসস্ট্রিং শিরোলেখ ফাইলটিতে পদ্ধতিগুলি পাওয়া গেছে।


সুইফট 3.0.০.২ এর জন্য নিম্নলিখিত উত্তরটি সবচেয়ে সহজ:

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

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

এটি আপডেট করা রেঞ্জ সহ আমার স্থির।





emoji