0

How can emojis also be filtered out of string using the following extension?

extension String {
    func removeCharacters() -> String {
        let removeCharacters: CharacterSet = [" ", ";", ",", ":", ".", "!", "%", "$", "&", "#", "*", "^", "@", "(", ")", "/"]
        let filteredString = self.unicodeScalars.filter { !removeCharacters.contains($0) }
        return String(String.UnicodeScalarView(filteredString))
    }
}

I understand isEmojiPresentation == false property can be used, just not sure how to add it to the function. To clarify all emoji should be removed from strings passed through the extension.

pkamb
  • 30,595
  • 22
  • 143
  • 179
Daniel
  • 1
  • 6
  • 13
  • 2
    You should spend some more time reading about how `filter` works – Alexander Aug 19 '21 at 19:09
  • @Alexander I have already posted what OP needs to make filter return any type that conform to `RangeReplaceableCollection` in this case a String but not sure why he is asking that again https://stackoverflow.com/a/68852194/2303865 – Leo Dabus Aug 19 '21 at 19:11
  • 3
    @LeoDabus It's a pretty clear cut case of BSODD: blind StackOverflow-driven development. – Alexander Aug 19 '21 at 19:15

1 Answers1

0

You need to access the Unicode.Scalar's property properties. Btw filter on a UnicodeScalarView already returns a UnicodeScalarView:

extension String {
    func removeCharacters() -> String {
        let removeCharacters: CharacterSet = .init(charactersIn: " ;,:.!%$&#*^@()/")
        return .init(
            unicodeScalars.filter {
                !removeCharacters.contains($0) &&
                $0.properties.isEmojiPresentation == false
            }
        )
    }
}

edit/update:

The reason a digit would return true for isEmoji is explained in the docs isEmoji

The final result is true because the ASCII digits have non-default emoji presentations; some platforms render these with an alternate appearance.

You can avoid removing them from your string adding an extra condition to your filter method:

extension RangeReplaceableCollection where Self: StringProtocol {
    var removingEmoji: Self  {
        filter { !($0.unicodeScalars.first?.properties.isEmoji == true && !("0"..."9" ~= $0)) }
    }
}

let noEmoji = "abc123".removingEmoji

noEmoji  // "abc123"

Expanding on that:

extension Character {
    var isEmoji: Bool { unicodeScalars.first?.properties.isEmoji == true && !isDigit }
    var isDigit: Bool { "0"..."9" ~= self }
    var isNotEmoji: Bool { !isEmoji }
}

extension RangeReplaceableCollection where Self: StringProtocol {
    var removingEmoji: Self  { filter(\.isNotEmoji) }
    var emojis: Self  { filter(\.isEmoji) }
}

Playground testing:

let notEmoji = "abc✈️123".removingEmoji
notEmoji  // "abc123"
let emojis = "abc✈️123".emojis
emojis  // "✈️"
Leo Dabus
  • 216,610
  • 56
  • 458
  • 536