Swift turn a country code into a emoji flag via unicode

后端 未结 7 843
日久生厌
日久生厌 2020-12-07 14:08

I\'m looking for a quick way to turn something like:

let germany = \"DE\" 

into

let flag = \"\\u{1f1e9}\\u{1f1ea}\"
         


        
相关标签:
7条回答
  • 2020-12-07 14:19

    Two optimizations of matt's answer.

    • No need to pass through the nested String in Swift 4
    • To avoid pass lower case string, I added uppercased()

    Here is the code.

    func flag(from country:String) -> String {
        let base : UInt32 = 127397
        var s = ""
        for v in country.uppercased().unicodeScalars {
            s.unicodeScalars.append(UnicodeScalar(base + v.value)!)
        }
        return s
    }
    
    0 讨论(0)
  • 2020-12-07 14:24

    If anyone looking for solution in ObjectiveC here is convenient category:

    @interface NSLocale (RREmoji)
    
    + (NSString *)emojiFlagForISOCountryCode:(NSString *)countryCode;
    
    @end
    
    
    @implementation NSLocale (RREmoji)
    
    
    + (NSString *)emojiFlagForISOCountryCode:(NSString *)countryCode {
        NSAssert(countryCode.length == 2, @"Expecting ISO country code");
    
        int base = 127462 -65;
    
        wchar_t bytes[2] = {
            base +[countryCode characterAtIndex:0],
            base +[countryCode characterAtIndex:1]
        };
    
        return [[NSString alloc] initWithBytes:bytes
                                        length:countryCode.length *sizeof(wchar_t)
                                      encoding:NSUTF32LittleEndianStringEncoding];
    }
    
    
    @end
    

    test:

    for ( NSString *countryCode in [NSLocale ISOCountryCodes] ) {
        NSLog(@"%@ - %@", [NSLocale emojiFlagForISOCountryCode:countryCode], countryCode);
    }
    

    output:

    0 讨论(0)
  • 2020-12-07 14:27

    I know this is not exactly what was asked, but maybe it will help someone:

    var flagDictionary: [String: String] = [
      "AD": "                                                                    
    0 讨论(0)
  • 2020-12-07 14:28

    Here's a general formula for turning a two-letter country code into its emoji flag:

    func flag(country:String) -> String {
        let base = 127397
        var usv = String.UnicodeScalarView()
        for i in country.utf16 {
            usv.append(UnicodeScalar(base + Int(i)))
        }
        return String(usv)
    }
    
    let s = flag("DE")
    

    EDIT Ooops, no need to pass through the nested String.UnicodeScalarView struct. It turns out that String has an append method for precisely this purpose. So:

    func flag(country:String) -> String { 
        let base : UInt32 = 127397
        var s = ""
        for v in country.unicodeScalars {
            s.append(UnicodeScalar(base + v.value))
        }
        return s
    }
    

    EDIT Oooops again, in Swift 3 they took away the ability to append a UnicodeScalar to a String, and they made the UnicodeScalar initializer failable (Xcode 8 seed 6), so now it looks like this:

    func flag(country:String) -> String {
        let base : UInt32 = 127397
        var s = ""
        for v in country.unicodeScalars {
            s.unicodeScalars.append(UnicodeScalar(base + v.value)!)
        }
        return String(s)
    }
    
    0 讨论(0)
  • 2020-12-07 14:29

    To give more insight into matt answer

    Swift 2 version

    public static func flag(countryCode: String) -> Character {
        let base = UnicodeScalar("                                                                    
    0 讨论(0)
  • 2020-12-07 14:30

    For a more functional approach, using no mutable variables, use this:

    private func flag(country: String) -> String {
        let base: UInt32 = 127397
        return country.unicodeScalars
            .flatMap({ UnicodeScalar(base + $0.value) })
            |> String.UnicodeScalarView.init
            |> String.init
    }
    

    Where the |> operator is the function application operator, working like a "pipe" for a more natural reading order: We take the scalars, map them into new scalars, turn that into a view, and that into a string.

    It's defined like so:

    infix operator |> : MultiplicationPrecedence
    func |> <T, U>(left: T, right: (T) -> U) -> U {
        return right(left)
    }
    

    Without custom operators, we can still do without mutable state, like so:

    private func flag(country: String) -> String {
        let base: UInt32 = 127397
        return String(String.UnicodeScalarView(
            country.unicodeScalars.flatMap({ UnicodeScalar(base + $0.value) })
        ))
    }
    

    But IMHO, this reads a little "backwards", since the natural flow of operations read neither out-in, nor in-out, but a little bit of both.

    0 讨论(0)
提交回复
热议问题