mirror of
https://github.com/mii443/AzooKeyKanaKanjiConverter.git
synced 2025-12-03 02:58:27 +00:00
Move to root
This commit is contained in:
69
Sources/SwiftUtils/AppVersion.swift
Normal file
69
Sources/SwiftUtils/AppVersion.swift
Normal file
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// AppVersion.swift
|
||||
// azooKey
|
||||
//
|
||||
// Created by ensan on 2022/07/02.
|
||||
// Copyright © 2022 ensan. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// AppVersion is a struct that represents a version of an app.
|
||||
/// It is a wrapper of String that conforms to Codable, Equatable, Comparable, Hashable, LosslessStringConvertible, CustomStringConvertible.
|
||||
/// It is initialized with a string that represents a version of an app.
|
||||
/// The string must be in the format of "major.minor.patch".
|
||||
/// The string must not contain any other characters than numbers and dots.
|
||||
public struct AppVersion: Codable, Equatable, Comparable, Hashable, LosslessStringConvertible, CustomStringConvertible {
|
||||
|
||||
/// ParseError is an enum that represents an error that occurs when parsing a string to an AppVersion.
|
||||
private enum ParseError: Error {
|
||||
case nonIntegerValue
|
||||
}
|
||||
|
||||
/// Initializes an AppVersion with a string that represents a version of an app.
|
||||
public init?(_ description: String) {
|
||||
if let versionSequence = try? description.split(separator: ".").map({ (value: Substring) throws -> Int in
|
||||
guard let value = Int(value) else { throw ParseError.nonIntegerValue }
|
||||
return value
|
||||
}) {
|
||||
if versionSequence.count < 1 {
|
||||
self.majorVersion = 0
|
||||
} else {
|
||||
self.majorVersion = versionSequence[0]
|
||||
}
|
||||
|
||||
if versionSequence.count < 2 {
|
||||
self.minorVersion = 0
|
||||
} else {
|
||||
self.minorVersion = versionSequence[1]
|
||||
}
|
||||
|
||||
if versionSequence.count < 3 {
|
||||
self.patchVersion = 0
|
||||
} else {
|
||||
self.patchVersion = versionSequence[2]
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
/// Compares two AppVersions.
|
||||
public static func < (lhs: AppVersion, rhs: AppVersion) -> Bool {
|
||||
for (l, r) in zip([lhs.majorVersion, lhs.minorVersion, lhs.patchVersion], [rhs.majorVersion, rhs.minorVersion, rhs.patchVersion]) {
|
||||
if l == r {
|
||||
continue
|
||||
}
|
||||
return l < r
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public var majorVersion: Int
|
||||
public var minorVersion: Int
|
||||
public var patchVersion: Int
|
||||
|
||||
public var description: String {
|
||||
"\(majorVersion).\(minorVersion).\(patchVersion)"
|
||||
}
|
||||
}
|
||||
128
Sources/SwiftUtils/ArrayUtils.swift
Normal file
128
Sources/SwiftUtils/ArrayUtils.swift
Normal file
@@ -0,0 +1,128 @@
|
||||
//
|
||||
// ArrayUtils.swift
|
||||
//
|
||||
//
|
||||
// Created by ensan on 2023/04/30.
|
||||
//
|
||||
|
||||
import Algorithms
|
||||
import Foundation
|
||||
|
||||
@resultBuilder
|
||||
public struct ArrayBuilder {
|
||||
public static func buildBlock<T>(_ values: T...) -> [T] {
|
||||
values
|
||||
}
|
||||
}
|
||||
|
||||
public extension Sequence {
|
||||
/// Returns a sequence that contains the elements of this sequence followed by the elements of the given sequence.
|
||||
/// - Parameters:
|
||||
/// - sequence: A sequence of elements to chain.
|
||||
/// - Returns: A sequence that contains the elements of this sequence followed by the elements of the given sequence.
|
||||
@inlinable func chained<S: Sequence<Element>>(_ sequence: S) -> Chain2Sequence<Self, S> {
|
||||
chain(self, sequence)
|
||||
}
|
||||
}
|
||||
|
||||
public extension Collection {
|
||||
/// Returns a `Set` containing the elements of this sequence with transformed values.
|
||||
/// - Parameters:
|
||||
/// - transform: A closure that transforms each element of this sequence into a value that can be hashed.
|
||||
/// - Returns: A `Set` containing the elements of this sequence.
|
||||
@inlinable func mapSet<T>(transform closure: (Element) throws -> T) rethrows -> Set<T> {
|
||||
var set = Set<T>()
|
||||
set.reserveCapacity(self.count)
|
||||
for item in self {
|
||||
set.update(with: try closure(item))
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
/// Returns a `Set` containing the elements of this sequence with transformed values.
|
||||
/// - Parameters:
|
||||
/// - transform: A closure that transforms each element of this sequence into a sequence of values that can be hashed.
|
||||
/// - Returns: A `Set` containing the elements of this sequence.
|
||||
@inlinable func flatMapSet<T: Sequence>(transform closure: (Element) throws -> T) rethrows -> Set<T.Element> {
|
||||
var set = Set<T.Element>()
|
||||
for item in self {
|
||||
set.formUnion(try closure(item))
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
/// Returns a `Set` containing the non-nil elements of this sequence with transformed values.
|
||||
/// - Parameters:
|
||||
/// - transform: A closure that transforms each element of this sequence into an optional value that can be hashed.
|
||||
/// - Returns: A `Set` containing the non-nil elements of this sequence.
|
||||
@inlinable func compactMapSet<T>(transform closure: (Element) throws -> T?) rethrows -> Set<T> {
|
||||
var set = Set<T>()
|
||||
set.reserveCapacity(self.count)
|
||||
for item in self {
|
||||
if let value = try closure(item) {
|
||||
set.update(with: value)
|
||||
}
|
||||
}
|
||||
return set
|
||||
}
|
||||
}
|
||||
|
||||
public extension MutableCollection {
|
||||
/// Calls the given closure with a pointer to the array's mutable contiguous storage.
|
||||
/// - Parameter
|
||||
/// - transform: A closure that takes a pointer to the array's mutable contiguous storage.
|
||||
@inlinable mutating func mutatingForeach(transform closure: (inout Element) throws -> Void) rethrows {
|
||||
for index in self.indices {
|
||||
try closure(&self[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension Collection {
|
||||
/// Returns a SubSequence containing the elements of this sequence up to the first element that does not satisfy the given predicate.
|
||||
/// - Parameters:
|
||||
/// - condition: A closure that takes an element of the sequence as its argument and returns a Boolean value indicating whether the element should be included.
|
||||
/// - Returns: A SubSequence containing the elements of this sequence up to the first element that does not satisfy the given predicate.
|
||||
@inlinable func suffix(while condition: (Element) -> Bool) -> SubSequence {
|
||||
var left = self.endIndex
|
||||
while left != self.startIndex, condition(self[self.index(left, offsetBy: -1)]) {
|
||||
left = self.index(left, offsetBy: -1)
|
||||
}
|
||||
return self[left ..< self.endIndex]
|
||||
}
|
||||
}
|
||||
|
||||
public extension Collection where Self.Element: Equatable {
|
||||
/// Returns a Bool value indicating whether the collection has the given suffix.
|
||||
/// - Parameters:
|
||||
/// - suffix: A collection to search for at the end of this collection.
|
||||
/// - Returns: A Bool value indicating whether the collection has the given suffix.
|
||||
@inlinable func hasSuffix(_ suffix: some Collection<Element>) -> Bool {
|
||||
if self.count < suffix.count {
|
||||
return false
|
||||
}
|
||||
let count = suffix.count
|
||||
for (i, value) in suffix.enumerated() {
|
||||
if self[self.index(self.endIndex, offsetBy: i - count)] != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/// Returns an Array containing the common prefix of this collection and the given collection.
|
||||
/// - Parameters:
|
||||
/// - collection: A collection to search for a common prefix with this collection.
|
||||
/// - Returns: An Array containing the common prefix of this collection and the given collection.
|
||||
@inlinable func commonPrefix(with collection: some Collection<Element>) -> [Element] {
|
||||
var prefix: [Element] = []
|
||||
for (i, value) in self.enumerated() where i < collection.count {
|
||||
if value == collection[collection.index(collection.startIndex, offsetBy: i)] {
|
||||
prefix.append(value)
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
return prefix
|
||||
}
|
||||
}
|
||||
314
Sources/SwiftUtils/CharacterUtils.swift
Normal file
314
Sources/SwiftUtils/CharacterUtils.swift
Normal file
@@ -0,0 +1,314 @@
|
||||
//
|
||||
// extension Character.swift
|
||||
// Keyboard
|
||||
//
|
||||
// Created by ensan on 2020/09/03.
|
||||
// Copyright © 2020 ensan. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum CharacterUtils {
|
||||
/// 小書きのかなカナ集合
|
||||
private static let kogakiKana: Set<Character> = [
|
||||
"ぁ", "ぃ", "ぅ", "ぇ", "ぉ", "ゕ", "ゖ", "っ", "ゃ", "ゅ", "ょ", "ゎ",
|
||||
"ァ", "ィ", "ゥ", "ェ", "ォ", "ヵ", "ヶ", "ッ", "ャ", "ュ", "ョ", "ヮ"
|
||||
]
|
||||
/// 濁点付きのかなカナ集合
|
||||
private static let dakutenKana: Set<Character> = [
|
||||
"ゔ", "が", "ぎ", "ぐ", "げ", "ご", "ざ", "じ", "ず", "ぜ", "ぞ", "だ", "ぢ", "づ", "で", "ど", "ば", "び", "ぶ", "べ", "ぼ",
|
||||
"ヴ", "ガ", "ギ", "グ", "ゲ", "ゴ", "ザ", "ジ", "ズ", "ゼ", "ゾ", "ダ", "ヂ", "ヅ", "デ", "ド", "バ", "ビ", "ブ", "ベ", "ボ"
|
||||
]
|
||||
|
||||
/// 小書きかなか否か
|
||||
static func isKogana(_ character: Character) -> Bool {
|
||||
kogakiKana.contains(character)
|
||||
}
|
||||
|
||||
/// ローマ字(a-z, A-Zか否か)
|
||||
@inlinable public static func isRomanLetter(_ character: Character) -> Bool {
|
||||
character.isASCII && character.isCased
|
||||
}
|
||||
|
||||
/// 自分が小書きであれば該当する文字を返す。
|
||||
public static func kogaki(_ character: Character) -> Character {
|
||||
switch character {
|
||||
case "あ":return "ぁ"
|
||||
case "い":return "ぃ"
|
||||
case "う":return "ぅ"
|
||||
case "え":return "ぇ"
|
||||
case "お":return "ぉ"
|
||||
case "か":return "ゕ"
|
||||
case "け":return "ゖ"
|
||||
case "つ":return "っ"
|
||||
case "や":return "ゃ"
|
||||
case "ゆ":return "ゅ"
|
||||
case "よ":return "ょ"
|
||||
case "わ":return "ゎ"
|
||||
case "ア":return "ァ"
|
||||
case "イ":return "ィ"
|
||||
case "ウ":return "ゥ"
|
||||
case "エ":return "ェ"
|
||||
case "オ":return "ォ"
|
||||
case "カ":return "ヵ"
|
||||
case "ケ":return "ヶ"
|
||||
case "ツ":return "ッ"
|
||||
case "ヤ":return "ャ"
|
||||
case "ユ":return "ュ"
|
||||
case "ヨ":return "ョ"
|
||||
case "ワ":return "ヮ"
|
||||
default: return character
|
||||
}
|
||||
}
|
||||
|
||||
/// 小書きから大書きを返す
|
||||
public static func ogaki(_ character: Character) -> Character {
|
||||
switch character {
|
||||
case "ぁ":return "あ"
|
||||
case "ぃ":return "い"
|
||||
case "ぅ":return "う"
|
||||
case "ぇ":return "え"
|
||||
case "ぉ":return "お"
|
||||
case "ゕ":return "か"
|
||||
case "ゖ":return "け"
|
||||
case "っ":return "つ"
|
||||
case "ゃ":return "や"
|
||||
case "ゅ":return "ゆ"
|
||||
case "ょ":return "よ"
|
||||
case "ゎ":return "わ"
|
||||
case "ァ":return "ア"
|
||||
case "ィ":return "イ"
|
||||
case "ゥ":return "ウ"
|
||||
case "ェ":return "エ"
|
||||
case "ォ":return "オ"
|
||||
case "ヵ":return "カ"
|
||||
case "ヶ":return "ケ"
|
||||
case "ッ":return "ツ"
|
||||
case "ャ":return "ヤ"
|
||||
case "ュ":return "ユ"
|
||||
case "ョ":return "ヨ"
|
||||
case "ヮ":return "ワ"
|
||||
default: return character
|
||||
}
|
||||
}
|
||||
|
||||
/// 濁点付きか否か
|
||||
public static func isDakuten(_ character: Character) -> Bool {
|
||||
dakutenKana.contains(character)
|
||||
}
|
||||
/// 濁点をつけて返す
|
||||
public static func dakuten(_ character: Character) -> Character {
|
||||
switch character {
|
||||
case"う":return "ゔ"
|
||||
case"か":return "が"
|
||||
case"き":return "ぎ"
|
||||
case"く":return "ぐ"
|
||||
case"け":return "げ"
|
||||
case"こ":return "ご"
|
||||
case"さ":return "ざ"
|
||||
case"し":return "じ"
|
||||
case"す":return "ず"
|
||||
case"せ":return "ぜ"
|
||||
case"そ":return "ぞ"
|
||||
case"た":return "だ"
|
||||
case"ち":return "ぢ"
|
||||
case"つ":return "づ"
|
||||
case"て":return "で"
|
||||
case"と":return "ど"
|
||||
case"は":return "ば"
|
||||
case"ひ":return "び"
|
||||
case"ふ":return "ぶ"
|
||||
case"へ":return "べ"
|
||||
case"ほ":return "ぼ"
|
||||
case"ウ":return "ヴ"
|
||||
case"カ":return "ガ"
|
||||
case"キ":return "ギ"
|
||||
case"ク":return "グ"
|
||||
case"ケ":return "ゲ"
|
||||
case"コ":return "ゴ"
|
||||
case"サ":return "ザ"
|
||||
case"シ":return "ジ"
|
||||
case"ス":return "ズ"
|
||||
case"セ":return "ゼ"
|
||||
case"ソ":return "ゾ"
|
||||
case"タ":return "ダ"
|
||||
case"チ":return "ヂ"
|
||||
case"ツ":return "ヅ"
|
||||
case"テ":return "デ"
|
||||
case"ト":return "ド"
|
||||
case"ハ":return "バ"
|
||||
case"ヒ":return "ビ"
|
||||
case"フ":return "ブ"
|
||||
case"ヘ":return "ベ"
|
||||
case"ホ":return "ボ"
|
||||
default: return character
|
||||
}
|
||||
}
|
||||
/// 濁点を外して返す
|
||||
public static func mudakuten(_ character: Character) -> Character {
|
||||
switch character {
|
||||
case"ゔ":return "う"
|
||||
case"が":return "か"
|
||||
case"ぎ":return "き"
|
||||
case"ぐ":return "く"
|
||||
case"げ":return "け"
|
||||
case"ご":return "こ"
|
||||
case"ざ":return "さ"
|
||||
case"じ":return "し"
|
||||
case"ず":return "す"
|
||||
case"ぜ":return "せ"
|
||||
case"ぞ":return "そ"
|
||||
case"だ":return "た"
|
||||
case"ぢ":return "ち"
|
||||
case"づ":return "つ"
|
||||
case"で":return "て"
|
||||
case"ど":return "と"
|
||||
case"ば":return "は"
|
||||
case"び":return "ひ"
|
||||
case"ぶ":return "ふ"
|
||||
case"べ":return "へ"
|
||||
case"ぼ":return "ほ"
|
||||
case"ヴ":return "ウ"
|
||||
case"ガ":return "カ"
|
||||
case"ギ":return "キ"
|
||||
case"グ":return "ク"
|
||||
case"ゲ":return "ケ"
|
||||
case"ゴ":return "コ"
|
||||
case"ザ":return "サ"
|
||||
case"ジ":return "シ"
|
||||
case"ズ":return "ス"
|
||||
case"ゼ":return "セ"
|
||||
case"ゾ":return "ソ"
|
||||
case"ダ":return "タ"
|
||||
case"ヂ":return "チ"
|
||||
case"ヅ":return "ツ"
|
||||
case"デ":return "テ"
|
||||
case"ド":return "ト"
|
||||
case"バ":return "ハ"
|
||||
case"ビ":return "ヒ"
|
||||
case"ブ":return "フ"
|
||||
case"ベ":return "ヘ"
|
||||
case"ボ":return "ホ"
|
||||
default: return character
|
||||
}
|
||||
}
|
||||
/// 半濁点かどうか
|
||||
public static func isHandakuten(_ character: Character) -> Bool {
|
||||
[
|
||||
"ぱ", "ぴ", "ぷ", "ぺ", "ぽ",
|
||||
"パ", "ピ", "プ", "ペ", "ポ"
|
||||
].contains(character)
|
||||
}
|
||||
/// 半濁点をつけて返す
|
||||
public static func handakuten(_ character: Character) -> Character {
|
||||
switch character {
|
||||
case"は":return "ぱ"
|
||||
case"ひ":return "ぴ"
|
||||
case"ふ":return "ぷ"
|
||||
case"へ":return "ぺ"
|
||||
case"ほ":return "ぽ"
|
||||
case"ハ":return "パ"
|
||||
case"ヒ":return "ピ"
|
||||
case"フ":return "プ"
|
||||
case"ヘ":return "ペ"
|
||||
case"ホ":return "ポ"
|
||||
default: return character
|
||||
}
|
||||
}
|
||||
/// 半濁点を外して返す
|
||||
public static func muhandakuten(_ character: Character) -> Character {
|
||||
switch character {
|
||||
case"ぱ":return "は"
|
||||
case"ぴ":return "ひ"
|
||||
case"ぷ":return "ふ"
|
||||
case"ぺ":return "へ"
|
||||
case"ぽ":return "ほ"
|
||||
case"パ":return "ハ"
|
||||
case"ピ":return "ヒ"
|
||||
case"プ":return "フ"
|
||||
case"ペ":return "ヘ"
|
||||
case"ポ":return "ホ"
|
||||
default: return character
|
||||
}
|
||||
}
|
||||
|
||||
/// 濁点、小書き、半濁点などを相互に変換する関数。
|
||||
public static func requestChange(_ character: Character) -> String {
|
||||
if character.isLowercase {
|
||||
return character.uppercased()
|
||||
}
|
||||
if character.isUppercase {
|
||||
return character.lowercased()
|
||||
}
|
||||
|
||||
if Set(["あ", "い", "え", "お", "や", "ゆ", "よ", "わ"]).contains(character) {
|
||||
return String(kogaki(character))
|
||||
}
|
||||
|
||||
if Set(["ぁ", "ぃ", "ぇ", "ぉ", "ゃ", "ゅ", "ょ", "ゎ"]).contains(character) {
|
||||
return String(ogaki(character))
|
||||
}
|
||||
|
||||
if Set(["か", "き", "く", "け", "こ", "さ", "し", "す", "せ", "そ", "た", "ち", "て", "と"]).contains(character) {
|
||||
return String(dakuten(character))
|
||||
}
|
||||
|
||||
if Set(["が", "ぎ", "ぐ", "げ", "ご", "ざ", "じ", "ず", "ぜ", "ぞ", "だ", "ぢ", "で", "ど"]).contains(character) {
|
||||
return String(mudakuten(character))
|
||||
}
|
||||
|
||||
if Set(["つ", "う"]).contains(character) {
|
||||
return String(kogaki(character))
|
||||
}
|
||||
|
||||
if Set(["っ", "ぅ"]).contains(character) {
|
||||
return String(dakuten(ogaki(character)))
|
||||
}
|
||||
|
||||
if Set(["づ", "ゔ"]).contains(character) {
|
||||
return String(mudakuten(character))
|
||||
}
|
||||
|
||||
if Set(["は", "ひ", "ふ", "へ", "ほ"]).contains(character) {
|
||||
return String(dakuten(character))
|
||||
}
|
||||
|
||||
if Set(["ば", "び", "ぶ", "べ", "ぼ"]).contains(character) {
|
||||
return String(handakuten(mudakuten(character)))
|
||||
}
|
||||
|
||||
if Set(["ぱ", "ぴ", "ぷ", "ぺ", "ぽ"]).contains(character) {
|
||||
return String(muhandakuten(character))
|
||||
}
|
||||
|
||||
return String(character)
|
||||
}
|
||||
}
|
||||
|
||||
public extension Character {
|
||||
/// Returns the Katakanized version of the character.
|
||||
@inlinable func toKatakana() -> Character {
|
||||
if self.unicodeScalars.count != 1 {
|
||||
return self
|
||||
}
|
||||
let scalar = self.unicodeScalars.first!
|
||||
if 0x3041 <= scalar.value && scalar.value <= 0x3096 {
|
||||
return Character(UnicodeScalar(scalar.value + 96)!)
|
||||
} else {
|
||||
return self
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Hiraganized version of the character.
|
||||
@inlinable func toHiragana() -> Character {
|
||||
if self.unicodeScalars.count != 1 {
|
||||
return self
|
||||
}
|
||||
let scalar = self.unicodeScalars.first!
|
||||
if 0x30A1 <= scalar.value && scalar.value <= 0x30F6 {
|
||||
return Character(UnicodeScalar(scalar.value - 96)!)
|
||||
} else {
|
||||
return self
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Sources/SwiftUtils/CodableSupport.swift
Normal file
18
Sources/SwiftUtils/CodableSupport.swift
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// CodableSupport.swift
|
||||
// azooKey
|
||||
//
|
||||
// Created by ensan on 2021/03/17.
|
||||
// Copyright © 2021 ensan. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension Encodable {
|
||||
/// Encodes this value into the given container.
|
||||
/// - Parameters:
|
||||
/// - container: The container to encode this value into.
|
||||
func containerEncode<CodingKeys: CodingKey>(container: inout KeyedEncodingContainer<CodingKeys>, key: CodingKeys) throws {
|
||||
try container.encode(self, forKey: key)
|
||||
}
|
||||
}
|
||||
26
Sources/SwiftUtils/DataUtils.swift
Normal file
26
Sources/SwiftUtils/DataUtils.swift
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// extension Data.swift
|
||||
// azooKey
|
||||
//
|
||||
// Created by ensan on 2022/10/22.
|
||||
// Copyright © 2022 ensan. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Data {
|
||||
/// Converts this data to an array of the given type.
|
||||
/// - Parameter:
|
||||
/// - type: The type to convert this data to.
|
||||
/// - Returns: An array of the given type.
|
||||
@inlinable public func toArray<T>(of type: T.Type) -> [T] {
|
||||
self.withUnsafeBytes {pointer -> [T] in
|
||||
Array(
|
||||
UnsafeBufferPointer(
|
||||
start: pointer.baseAddress!.assumingMemoryBound(to: type),
|
||||
count: pointer.count / MemoryLayout<T>.size
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Sources/SwiftUtils/Debug.swift
Normal file
79
Sources/SwiftUtils/Debug.swift
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Debug.swift
|
||||
//
|
||||
//
|
||||
// Created by ensan on 2023/04/30.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Prints the given items to the standard output if the build setting "DEBUG" is set.
|
||||
/// - Parameter:
|
||||
/// - items: The items to print.
|
||||
/// - Note: This function is always preferred over `print` in the codebase.
|
||||
@_disfavoredOverload
|
||||
@inlinable public func debug(_ items: Any...) {
|
||||
#if DEBUG
|
||||
var result = ""
|
||||
for value in items {
|
||||
if result.isEmpty {
|
||||
result.append("\(value)")
|
||||
} else {
|
||||
result.append(" ")
|
||||
result.append("\(value)")
|
||||
}
|
||||
}
|
||||
print(result)
|
||||
#endif
|
||||
}
|
||||
|
||||
@inlinable public func debug(_ item1: @autoclosure () -> Any) {
|
||||
#if DEBUG
|
||||
print(item1())
|
||||
#endif
|
||||
}
|
||||
@inlinable public func debug(_ item1: @autoclosure () -> Any, _ item2: @autoclosure () -> Any) {
|
||||
#if DEBUG
|
||||
print(item1(), item2())
|
||||
#endif
|
||||
}
|
||||
@inlinable public func debug(_ item1: @autoclosure () -> Any, _ item2: @autoclosure () -> Any, _ item3: @autoclosure () -> Any) {
|
||||
#if DEBUG
|
||||
print(item1(), item2(), item3())
|
||||
#endif
|
||||
}
|
||||
@inlinable public func debug(_ item1: @autoclosure () -> Any, _ item2: @autoclosure () -> Any, _ item3: @autoclosure () -> Any, _ item4: @autoclosure () -> Any) {
|
||||
#if DEBUG
|
||||
print(item1(), item2(), item3(), item4())
|
||||
#endif
|
||||
}
|
||||
@inlinable public func debug(_ item1: @autoclosure () -> Any, _ item2: @autoclosure () -> Any, _ item3: @autoclosure () -> Any, _ item4: @autoclosure () -> Any, _ item5: @autoclosure () -> Any) {
|
||||
#if DEBUG
|
||||
print(item1(), item2(), item3(), item4(), item5())
|
||||
#endif
|
||||
}
|
||||
@inlinable public func debug(_ item1: @autoclosure () -> Any, _ item2: @autoclosure () -> Any, _ item3: @autoclosure () -> Any, _ item4: @autoclosure () -> Any, _ item5: @autoclosure () -> Any, _ item6: @autoclosure () -> Any) {
|
||||
#if DEBUG
|
||||
print(item1(), item2(), item3(), item4(), item5(), item6())
|
||||
#endif
|
||||
}
|
||||
@inlinable public func debug(_ item1: @autoclosure () -> Any, _ item2: @autoclosure () -> Any, _ item3: @autoclosure () -> Any, _ item4: @autoclosure () -> Any, _ item5: @autoclosure () -> Any, _ item6: @autoclosure () -> Any, _ item7: @autoclosure () -> Any) {
|
||||
#if DEBUG
|
||||
print(item1(), item2(), item3(), item4(), item5(), item6(), item7())
|
||||
#endif
|
||||
}
|
||||
@inlinable public func debug(_ item1: @autoclosure () -> Any, _ item2: @autoclosure () -> Any, _ item3: @autoclosure () -> Any, _ item4: @autoclosure () -> Any, _ item5: @autoclosure () -> Any, _ item6: @autoclosure () -> Any, _ item7: @autoclosure () -> Any, _ item8: @autoclosure () -> Any) {
|
||||
#if DEBUG
|
||||
print(item1(), item2(), item3(), item4(), item5(), item6(), item7(), item8())
|
||||
#endif
|
||||
}
|
||||
@inlinable public func debug(_ item1: @autoclosure () -> Any, _ item2: @autoclosure () -> Any, _ item3: @autoclosure () -> Any, _ item4: @autoclosure () -> Any, _ item5: @autoclosure () -> Any, _ item6: @autoclosure () -> Any, _ item7: @autoclosure () -> Any, _ item8: @autoclosure () -> Any, _ item9: @autoclosure () -> Any) {
|
||||
#if DEBUG
|
||||
print(item1(), item2(), item3(), item4(), item5(), item6(), item7(), item8(), item9())
|
||||
#endif
|
||||
}
|
||||
@inlinable public func debug(_ item1: @autoclosure () -> Any, _ item2: @autoclosure () -> Any, _ item3: @autoclosure () -> Any, _ item4: @autoclosure () -> Any, _ item5: @autoclosure () -> Any, _ item6: @autoclosure () -> Any, _ item7: @autoclosure () -> Any, _ item8: @autoclosure () -> Any, _ item9: @autoclosure () -> Any, _ item10: @autoclosure () -> Any) {
|
||||
#if DEBUG
|
||||
print(item1(), item2(), item3(), item4(), item5(), item6(), item7(), item8(), item9(), item10())
|
||||
#endif
|
||||
}
|
||||
18
Sources/SwiftUtils/Modify.swift
Normal file
18
Sources/SwiftUtils/Modify.swift
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Modify.swift
|
||||
// azooKey
|
||||
//
|
||||
// Created by ensan on 2022/10/10.
|
||||
// Copyright © 2022 ensan. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Modifies the given value and returns the result.
|
||||
/// - Parameters:
|
||||
/// - value: The value to modify.
|
||||
/// - process: The process to modify the value.
|
||||
/// - Note: This function should be used when specific subscript setter is called for multiple times.
|
||||
@inlinable public func withMutableValue<T>(_ value: inout T, process: (inout T) -> Void) {
|
||||
process(&value)
|
||||
}
|
||||
117
Sources/SwiftUtils/StringUtils.swift
Normal file
117
Sources/SwiftUtils/StringUtils.swift
Normal file
@@ -0,0 +1,117 @@
|
||||
//
|
||||
// extension StringProtocol.swift
|
||||
// Keyboard
|
||||
//
|
||||
// Created by ensan on 2020/10/16.
|
||||
// Copyright © 2020 ensan. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension StringProtocol {
|
||||
/// ローマ字と数字のみかどうか
|
||||
/// - note: 空文字列の場合`false`を返す。
|
||||
@inlinable
|
||||
var onlyRomanAlphabetOrNumber: Bool {
|
||||
!isEmpty && range(of: "[^a-zA-Z0-9]", options: .regularExpression) == nil
|
||||
}
|
||||
/// ローマ字のみかどうか
|
||||
/// - note: 空文字列の場合`false`を返す。
|
||||
@inlinable
|
||||
var onlyRomanAlphabet: Bool {
|
||||
!isEmpty && range(of: "[^a-zA-Z]", options: .regularExpression) == nil
|
||||
}
|
||||
/// ローマ字を含むかどうか
|
||||
/// - note: 空文字列の場合`false`を返す。
|
||||
/// 以前は正規表現ベースで実装していたが、パフォーマンス上良くなかったので以下のような実装にしたところ40倍程度高速化した。
|
||||
@inlinable
|
||||
var containsRomanAlphabet: Bool {
|
||||
for value in self.utf8 {
|
||||
if (UInt8(ascii: "a") <= value && value <= UInt8(ascii: "z")) || (UInt8(ascii: "A") <= value && value <= UInt8(ascii: "Z")) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
/// 英語として許容可能な文字のみで構成されているか。
|
||||
/// - note: 空文字列の場合`false`を返す。
|
||||
@inlinable
|
||||
var isEnglishSentence: Bool {
|
||||
!isEmpty && range(of: "[^0-9a-zA-Z\n !'_<>\\[\\]{}*@`\\^|~=\"#$%&\\+\\(\\),\\-\\./:;?’\\\\]", options: .regularExpression) == nil
|
||||
}
|
||||
|
||||
/// 仮名か
|
||||
@inlinable
|
||||
var isKana: Bool {
|
||||
!isEmpty && range(of: "[^ぁ-ゖァ-ヶ]", options: .regularExpression) == nil
|
||||
}
|
||||
|
||||
/// Returns a String value in which Hiraganas are all converted to Katakana.
|
||||
/// - Returns: A String value in which Hiraganas are all converted to Katakana.
|
||||
@inlinable func toKatakana() -> String {
|
||||
// カタカナはutf16で常に2バイトなので、utf16単位で処理して良い
|
||||
let result = self.utf16.map { scalar -> UInt16 in
|
||||
if 0x3041 <= scalar && scalar <= 0x3096 {
|
||||
return scalar + 96
|
||||
} else {
|
||||
return scalar
|
||||
}
|
||||
}
|
||||
return String(utf16CodeUnits: result, count: result.count)
|
||||
}
|
||||
|
||||
/// Returns a String value in which Katakana are all converted to Hiragana.
|
||||
/// - Returns: A String value in which Katakana are all converted to Hiragana.
|
||||
@inlinable func toHiragana() -> String {
|
||||
// ひらがなはutf16で常に2バイトなので、utf16単位で処理して良い
|
||||
let result = self.utf16.map { scalar -> UInt16 in
|
||||
if 0x30A1 <= scalar && scalar <= 0x30F6 {
|
||||
return scalar - 96
|
||||
} else {
|
||||
return scalar
|
||||
}
|
||||
}
|
||||
return String(utf16CodeUnits: result, count: result.count)
|
||||
}
|
||||
|
||||
/// Returns an Index value that is the specified distance from the start index.
|
||||
/// - Parameter:
|
||||
/// - offset: The distance to offset from the start index.
|
||||
/// - Returns: An Index value that is the specified distance from the start index.
|
||||
@inlinable
|
||||
func indexFromStart(_ offset: Int) -> Index {
|
||||
self.index(self.startIndex, offsetBy: offset)
|
||||
}
|
||||
|
||||
// エスケープが必要なのは次の文字:
|
||||
/*
|
||||
\ -> \\
|
||||
\0 -> \0
|
||||
\n -> \n
|
||||
\t -> \t
|
||||
, -> \c
|
||||
" -> \d
|
||||
*/
|
||||
// please use these letters in order to avoid user-inputting text crash
|
||||
func escaped() -> String {
|
||||
var result = self.replacingOccurrences(of: "\\", with: "\\b")
|
||||
result = result.replacingOccurrences(of: "\0", with: "\\0")
|
||||
result = result.replacingOccurrences(of: "\n", with: "\\n")
|
||||
result = result.replacingOccurrences(of: "\t", with: "\\t")
|
||||
result = result.replacingOccurrences(of: ",", with: "\\c")
|
||||
result = result.replacingOccurrences(of: " ", with: "\\s")
|
||||
result = result.replacingOccurrences(of: "\"", with: "\\d")
|
||||
return result
|
||||
}
|
||||
|
||||
func unescaped() -> String {
|
||||
var result = self.replacingOccurrences(of: "\\d", with: "\"")
|
||||
result = result.replacingOccurrences(of: "\\s", with: " ")
|
||||
result = result.replacingOccurrences(of: "\\c", with: ",")
|
||||
result = result.replacingOccurrences(of: "\\t", with: "\t")
|
||||
result = result.replacingOccurrences(of: "\\n", with: "\n")
|
||||
result = result.replacingOccurrences(of: "\\0", with: "\0")
|
||||
result = result.replacingOccurrences(of: "\\b", with: "\\")
|
||||
return result
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user