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 // "✈️"