web-dev-qa-db-fra.com

Transformez rapidement un code pays en drapeau emoji via Unicode

Je cherche un moyen rapide de transformer quelque chose comme:

let germany = "DE" 

dans

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

c'est-à-dire, quel est le mappage de D sur 1f1e9 et de E sur 1f1ea Je cherchais .utf8 pour la chaîne, mais cela renvoie un entier. 

FWIW, mon objectif général est de pouvoir prendre un code de pays arbitraire et d’obtenir le drapeau emoji correspondant. 

EDIT: Je suis aussi très bien avec juste tenir une table qui fait cette cartographie si elle est disponible quelque part. J'ai cherché sur Google mais je ne l'ai pas trouvé.

37

Voici une formule générale pour transformer un code pays de deux lettres en drapeau emoji:

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

EDITOoops, inutile de passer par la structure imbriquée String.UnicodeScalarView. Il s'avère que String dispose d'une méthode append dans ce but précis. Alors:

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

EDITOooops à nouveau, dans Swift 3, ils ont perdu la possibilité d’ajouter un UnicodeScalar à une chaîne et ils ont rendu l’initialiseur UnicodeScalar disponible (Xcode 8 seed 6).

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)
}
61
matt

Si vous recherchez une solution dans ObjectiveC, voici une catégorie pratique:

@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

tester:

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

sortie:???????? - UN D???????? - AE ???????? - UN F???????? - AG ???????? - AI ...

17
RolandasR

Deux optimisations de la réponse de matt.

  • Pas besoin de passer par la chaîne imbriquée dans Swift 4
  • Pour éviter de passer la chaîne en minuscule, j'ai ajouté uppercased ()

Voici le 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
}
4
Lumialxk

Pour donner plus de perspicacité dans la réponse mate

Swift 2 version

public static func flag(countryCode: String) -> Character {
    let base = UnicodeScalar("????").value - UnicodeScalar("A").value

    let string = countryCode.uppercaseString.unicodeScalars.reduce("") {
      var string = $0
      string.append(UnicodeScalar(base + $1.value))
      return string
    }

    return Character(string)
  }

Version Swift 3, extraite de https://github.com/onmyway133/Smile/blob/master/Sources/Smile.Swift#L52

public func emoji(countryCode: String) -> Character {
  let base = UnicodeScalar("????").value - UnicodeScalar("A").value

  var string = ""
  countryCode.uppercased().unicodeScalars.forEach {
    if let scala = UnicodeScalar(base + $0.value) {
      string.append(String(describing: scala))
    }
  }

  return Character(string)
}
2
onmyway133

Pour une approche plus fonctionnelle, n'utilisant pas de variables mutables, utilisez ceci:

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

Où l'opérateur |> est l'opérateur d'application de la fonction, fonctionnant comme un "tuyau" pour un ordre de lecture plus naturel: nous prenons les scalaires, les mappons dans de nouveaux scalaires, transformons cela en vue, et cela en chaîne.

C'est défini comme suit:

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

Sans opérateurs personnalisés, on peut toujours se passer d'état mutable, comme ceci:

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

Mais à mon humble avis, cela se lit un peu "en arrière", car le flux naturel des opérations ne lit ni en entrée, ni en entrée, mais un peu des deux.

0

Comme d'habitude, @matt a la bonne réponse.

Sa solution pour Swift3 en utilisant flatMap et joined:

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

Ce que flatMap fait: Il mappe chaque unicodeScalar de country avec la base dans une nouvelle String qui est joined au résultat.

0