From 429f232af36da86878e36ffd21ed8616a1c215c6 Mon Sep 17 00:00:00 2001 From: Julian Gerhards <96697201+juliangerhards@users.noreply.github.com> Date: Thu, 9 Jun 2022 14:18:40 +0200 Subject: [PATCH] Added emoji String & Character extensions --- Sources/SwiftPlus/Extensions/Character.swift | 24 ++++++++++++++++++++ Sources/SwiftPlus/Extensions/String.swift | 21 +++++++++++++++++ Tests/SwiftPlusTests/SwiftPlusTests.swift | 16 +++++++++---- 3 files changed, 57 insertions(+), 4 deletions(-) create mode 100644 Sources/SwiftPlus/Extensions/Character.swift diff --git a/Sources/SwiftPlus/Extensions/Character.swift b/Sources/SwiftPlus/Extensions/Character.swift new file mode 100644 index 0000000..a7f1b86 --- /dev/null +++ b/Sources/SwiftPlus/Extensions/Character.swift @@ -0,0 +1,24 @@ +// +// File.swift +// +// +// Created by Julian Gerhards on 09.06.22. +// + +import Foundation + +public extension Character { + /// A simple emoji is one scalar and presented to the user as an Emoji + @available(iOS 10.2, *) + var isSimpleEmoji: Bool { + guard let firstScalar = unicodeScalars.first else { return false } + return firstScalar.properties.isEmoji && firstScalar.value > 0x238C + } + + /// Checks if the scalars will be merged into an emoji + @available(iOS 10.2, *) + var isCombinedIntoEmoji: Bool { unicodeScalars.count > 1 && unicodeScalars.first?.properties.isEmoji ?? false } + + @available(iOS 10.2, *) + var isEmoji: Bool { isSimpleEmoji || isCombinedIntoEmoji } +} diff --git a/Sources/SwiftPlus/Extensions/String.swift b/Sources/SwiftPlus/Extensions/String.swift index 7170e75..3414bac 100644 --- a/Sources/SwiftPlus/Extensions/String.swift +++ b/Sources/SwiftPlus/Extensions/String.swift @@ -90,4 +90,25 @@ public extension String { return mentions } + + /// Returns true if `String` is only a single emoji + @available(iOS 10.2, *) + var isSingleEmoji: Bool { count == 1 && containsEmoji } + + /// Returns true if `String` contains at least one emoji + @available(iOS 10.2, *) + var containsEmoji: Bool { contains { $0.isEmoji } } + + /// Returns true if `String` contains only emoji´s + @available(iOS 10.2, *) + var containsOnlyEmoji: Bool { !isEmpty && !contains { !$0.isEmoji } } + + @available(iOS 10.2, *) + var emojiString: String { emojis.map { String($0) }.reduce("", +) } + + @available(iOS 10.2, *) + var emojis: [Character] { filter { $0.isEmoji } } + + @available(iOS 10.2, *) + var emojiScalars: [UnicodeScalar] { filter { $0.isEmoji }.flatMap { $0.unicodeScalars } } } diff --git a/Tests/SwiftPlusTests/SwiftPlusTests.swift b/Tests/SwiftPlusTests/SwiftPlusTests.swift index 9cc69b0..9651f71 100644 --- a/Tests/SwiftPlusTests/SwiftPlusTests.swift +++ b/Tests/SwiftPlusTests/SwiftPlusTests.swift @@ -19,6 +19,7 @@ import XCTest @testable import SwiftPlus final class SwiftPlusTests: XCTestCase { + func test_double_extensions() throws { let double: Double = 1.494 @@ -28,11 +29,11 @@ final class SwiftPlusTests: XCTestCase { } func test_cgfloat_extensions() throws { - let double: CGFloat = 1.494 + let cgFloat: CGFloat = 1.494 - XCTAssertEqual(double.round(to: 2), 1.49) - XCTAssertEqual(double.maxValue(1.4), 1.4) - XCTAssertEqual(double.minValue(4.0), 4.0) + XCTAssertEqual(cgFloat.round(to: 2), 1.49) + XCTAssertEqual(cgFloat.maxValue(1.4), 1.4) + XCTAssertEqual(cgFloat.minValue(4.0), 4.0) } func test_string_extensions() throws { @@ -41,5 +42,12 @@ final class SwiftPlusTests: XCTestCase { XCTAssertEqual(string.trim(), "Hallo, mein #Name ist @String. Ich bin ein Swift-Typ.") XCTAssertEqual(string.getHashtags(), ["#Name": NSRange(location: 13, length: 5)]) XCTAssertEqual(string.getMentions(), ["@String": NSRange(location: 23, length: 7)]) + + if #available(iOS 10.2, *) { + XCTAssertEqual("☺️ Test".containsEmoji, true) + XCTAssertEqual("☺️ Test".containsOnlyEmoji, false) + XCTAssertEqual("☺️☺️".containsOnlyEmoji, true) + XCTAssertEqual("☺️".isSingleEmoji, true) + } } }