A small menubar app that allows you to switch between R versions quickly (if you have multiple versions of R framework installed). https://rud.is/rswitch
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

262 lines
8.4 KiB

//
// StringUtil.swift
// SwifSoup
//
// Created by Nabil Chatbi on 20/04/16.
// Copyright © 2016 Nabil Chatbi.. All rights reserved.
//
import Foundation
/**
* A minimal String utility class. Designed for internal jsoup use only.
*/
open class StringUtil {
enum StringError: Error {
case empty
case short
case error(String)
}
// memoised padding up to 10
fileprivate static let padding: [String] = ["", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]
private static let empty = ""
private static let space = " "
/**
* Join a collection of strings by a seperator
* @param strings collection of string objects
* @param sep string to place between strings
* @return joined string
*/
public static func join(_ strings: [String], sep: String) -> String {
return strings.joined(separator: sep)
}
public static func join(_ strings: Set<String>, sep: String) -> String {
return strings.joined(separator: sep)
}
public static func join(_ strings: OrderedSet<String>, sep: String) -> String {
return strings.joined(separator: sep)
}
// /**
// * Join a collection of strings by a seperator
// * @param strings iterator of string objects
// * @param sep string to place between strings
// * @return joined string
// */
// public static String join(Iterator strings, String sep) {
// if (!strings.hasNext())
// return ""
//
// String start = strings.next().toString()
// if (!strings.hasNext()) // only one, avoid builder
// return start
//
// StringBuilder sb = new StringBuilder(64).append(start)
// while (strings.hasNext()) {
// sb.append(sep)
// sb.append(strings.next())
// }
// return sb.toString()
// }
/**
* Returns space padding
* @param width amount of padding desired
* @return string of spaces * width
*/
public static func padding(_ width: Int) -> String {
if width <= 0 {
return empty
}
if width < padding.count {
return padding[width]
}
return String.init(repeating: space, count: width)
}
/**
* Tests if a string is blank: null, emtpy, or only whitespace (" ", \r\n, \t, etc)
* @param string string to test
* @return if string is blank
*/
public static func isBlank(_ string: String) -> Bool {
if (string.count == 0) {
return true
}
for chr in string {
if (!StringUtil.isWhitespace(chr)) {
return false
}
}
return true
}
/**
* Tests if a string is numeric, i.e. contains only digit characters
* @param string string to test
* @return true if only digit chars, false if empty or null or contains non-digit chrs
*/
public static func isNumeric(_ string: String) -> Bool {
if (string.count == 0) {
return false
}
for chr in string {
if !("0"..."9" ~= chr) {
return false
}
}
return true
}
/**
* Tests if a code point is "whitespace" as defined in the HTML spec.
* @param c code point to test
* @return true if code point is whitespace, false otherwise
*/
public static func isWhitespace(_ c: Character) -> Bool {
//(c == " " || c == UnicodeScalar.BackslashT || c == "\n" || (c == "\f" ) || c == "\r")
return c.isWhitespace
}
/**
* Normalise the whitespace within this string; multiple spaces collapse to a single, and all whitespace characters
* (e.g. newline, tab) convert to a simple space
* @param string content to normalise
* @return normalised string
*/
public static func normaliseWhitespace(_ string: String) -> String {
let sb: StringBuilder = StringBuilder.init()
appendNormalisedWhitespace(sb, string: string, stripLeading: false)
return sb.toString()
}
/**
* After normalizing the whitespace within a string, appends it to a string builder.
* @param accum builder to append to
* @param string string to normalize whitespace within
* @param stripLeading set to true if you wish to remove any leading whitespace
*/
public static func appendNormalisedWhitespace(_ accum: StringBuilder, string: String, stripLeading: Bool ) {
var lastWasWhite: Bool = false
var reachedNonWhite: Bool = false
for c in string {
if (isWhitespace(c)) {
if ((stripLeading && !reachedNonWhite) || lastWasWhite) {
continue
}
accum.append(" ")
lastWasWhite = true
} else {
accum.appendCodePoint(c)
lastWasWhite = false
reachedNonWhite = true
}
}
}
public static func inString(_ needle: String?, haystack: String...) -> Bool {
return inString(needle, haystack)
}
public static func inString(_ needle: String?, _ haystack: [String?]) -> Bool {
if(needle == nil) {return false}
for hay in haystack {
if(hay != nil && hay! == needle!) {
return true
}
}
return false
}
// open static func inSorted(_ needle: String, haystack: [String]) -> Bool {
// return binarySearch(haystack, searchItem: needle) >= 0
// }
//
// open static func binarySearch<T: Comparable>(_ inputArr: Array<T>, searchItem: T) -> Int {
// var lowerIndex = 0
// var upperIndex = inputArr.count - 1
//
// while (true) {
// let currentIndex = (lowerIndex + upperIndex)/2
// if(inputArr[currentIndex] == searchItem) {
// return currentIndex
// } else if (lowerIndex > upperIndex) {
// return -1
// } else {
// if (inputArr[currentIndex] > searchItem) {
// upperIndex = currentIndex - 1
// } else {
// lowerIndex = currentIndex + 1
// }
// }
// }
// }
/**
* Create a new absolute URL, from a provided existing absolute URL and a relative URL component.
* @param base the existing absolulte base URL
* @param relUrl the relative URL to resolve. (If it's already absolute, it will be returned)
* @return the resolved absolute URL
* @throws MalformedURLException if an error occurred generating the URL
*/
//NOTE: Not sure it work
public static func resolve(_ base: URL, relUrl: String ) -> URL? {
var base = base
if(base.pathComponents.count == 0 && base.absoluteString.last != "/" && !base.isFileURL) {
base = base.appendingPathComponent("/", isDirectory: false)
}
let u = URL(string: relUrl, relativeTo: base)
return u
}
/**
* Create a new absolute URL, from a provided existing absolute URL and a relative URL component.
* @param baseUrl the existing absolute base URL
* @param relUrl the relative URL to resolve. (If it's already absolute, it will be returned)
* @return an absolute URL if one was able to be generated, or the empty string if not
*/
public static func resolve(_ baseUrl: String, relUrl: String ) -> String {
let base = URL(string: baseUrl)
if(base == nil || base?.scheme == nil) {
let abs = URL(string: relUrl)
return abs != nil && abs?.scheme != nil ? abs!.absoluteURL.absoluteString : empty
} else {
let url = resolve(base!, relUrl: relUrl)
if(url != nil) {
let ext = url!.absoluteURL.absoluteString
return ext
}
if(base != nil && base?.scheme != nil) {
let ext = base!.absoluteString
return ext
}
return empty
}
// try {
// try {
// base = new URL(baseUrl)
// } catch (MalformedURLException e) {
// // the base is unsuitable, but the attribute/rel may be abs on its own, so try that
// URL abs = new URL(relUrl)
// return abs.toExternalForm()
// }
// return resolve(base, relUrl).toExternalForm()
// } catch (MalformedURLException e) {
// return ""
// }
}
}