ChWebsiteApp/CHDataManagement/Extensions/String+Extensions.swift
2024-12-06 21:59:36 +01:00

119 lines
3.6 KiB
Swift

extension String {
func htmlEscaped() -> String {
replacingOccurrences(of: "&", with: "&")
.replacingOccurrences(of: "\"", with: """)
.replacingOccurrences(of: "'", with: "'")
.replacingOccurrences(of: "<", with: "&lt;")
.replacingOccurrences(of: ">", with: "&gt;")
}
var nonEmpty: String? {
isEmpty ? nil : self
}
var trimmed: String {
trimmingCharacters(in: .whitespacesAndNewlines)
}
func indented(by indentation: String) -> String {
components(separatedBy: "\n").joined(separator: "\n" + indentation)
}
var withoutEmptyLines: String {
components(separatedBy: "\n")
.filter { !$0.trimmed.isEmpty }
.joined(separator: "\n")
}
/**
Remove the part after the last occurence of the separator (including the separator itself).
The string is left unchanges, if it does not contain the separator.
*/
func dropAfterLast(_ separator: String) -> String {
guard contains(separator) else {
return self
}
return components(separatedBy: separator).dropLast().joined(separator: separator)
}
func dropBeforeFirst(_ separator: String) -> String {
guard contains(separator) else {
return self
}
return components(separatedBy: separator).dropFirst().joined(separator: separator)
}
func lastComponentAfter(_ separator: String) -> String {
components(separatedBy: separator).last!
}
/**
Insert the new content before the last occurence of the specified separator.
If the separator does not appear in the string, then the new content is simply appended.
*/
func insert(_ content: String, beforeLast separator: String) -> String {
let parts = components(separatedBy: separator)
guard parts.count > 1 else {
return self + content
}
return parts.dropLast().joined(separator: separator) + content + separator + parts.last!
}
/**
Remove everything behind the first separator.
Also removes the separator itself. If the separator is not contained in the string, then the full string is returned.
*/
func dropAfterFirst<T>(_ separator: T) -> String where T: StringProtocol {
components(separatedBy: separator).first!
}
func between(_ start: String, and end: String) -> String {
dropBeforeFirst(start).dropAfterFirst(end)
}
}
extension String {
var fileExtension: String? {
let parts = components(separatedBy: ".")
guard parts.count > 1 else { return nil }
return parts.last
}
var fileNameAndExtension: (fileName: String, fileExtension: String?) {
let parts = components(separatedBy: ".")
guard parts.count > 1 else {
return (self, nil)
}
return (fileName: parts.dropLast().joined(separator: "."), fileExtension: parts.last)
}
}
extension Substring {
func dropBeforeFirst(_ separator: String) -> String {
guard contains(separator) else {
return String(self)
}
return components(separatedBy: separator).dropFirst().joined(separator: separator)
}
func between(_ start: String, and end: String) -> String {
components(separatedBy: start).last!
.components(separatedBy: end).first!
}
func between(first: String, andLast last: String) -> String {
dropBeforeFirst(first).dropAfterLast(last)
}
func last(after: String) -> String {
components(separatedBy: after).last!
}
}