Having no luck creating a partial range in Swift 4
import Foundation
public extension String {
public var URLScheme: String? {
guard let schemeRange = self.range(of: "://") else { return nil }
return self.substring(to: schemeRange.lowerBound)
}
public var URLPortNumber: Int {
guard let portRange = self.range(of: ":", options: .backwards) else { return -1 }
let startIndex = self.index(portRange.upperBound, offsetBy: 0)
let endIndex = self.index(portRange.upperBound, offsetBy: 2)
guard self[startIndex...endIndex] != "//" else { return -1 }
return Int(self.substring(from: portRange.upperBound))!
}
public var URLHost: String {
var host = self
if let scheme = self.URLScheme {
host = host.substring(from: self.index(self.startIndex, offsetBy: (scheme + "://").characters.count))
}
if let portRange = host.range(of: ":") {
host = host.substring(to: portRange.lowerBound)
}
return host
}
}
Also after reading the documentation on Substrings, I am still less than clear on their benefit. Has anyone used them for URLs?
Even the syntax is less succinct than dot notation.
This seems to work!
import Foundation
public extension String {
public var URLScheme: String? {
guard let schemeRange = self.range(of: "://") else { return nil }
return String(describing: schemeRange.lowerBound)
}
public var URLPortNumber: Int {
guard let portRange = self.range(of: ":", options: .backwards) else { return -1 }
let startIndex = self.index(portRange.upperBound, offsetBy: 0)
let endIndex = self.index(portRange.upperBound, offsetBy: 2)
guard self[startIndex...endIndex] != "//" else { return -1 }
return Int(String(describing: portRange.upperBound))!
}
public var URLHost: String {
var host = self
if let scheme = self.URLScheme {
host = String(describing: self.index(self.startIndex, offsetBy: (scheme + "://").characters.count))
}
if let portRange = host.range(of: ":") {
host = String(describing: portRange.lowerBound)
}
return host
}
}
Related
How to decode String from percent encoded windowsCP1251?
replacingPercentEscapes(using: String.Encoding.windowsCP1251) now is obsolete
removingPercentEncoding uses utf8
I have found the solution. It works for me. Welcome to refactor my example.
extension String {
func removingPercentEncoding(using encoding: String.Encoding) -> String {
let firstChar = self.first
let percentCharacter = Character("%")
var encodedPrefix: String.SubSequence? = nil
var encodedSuffix = self
if firstChar != percentCharacter {
if let indexOfFirstPercentChar = index(of: percentCharacter) {
encodedPrefix = self[..<indexOfFirstPercentChar]
encodedSuffix = String(self[indexOfFirstPercentChar...])
} else {
//no % char at all. Nothing encoded
return self
}
}
let substrings = encodedSuffix.components(separatedBy: "%")
let arr = substrings.map{ substring -> (String) in
switch substring.count {
case let count where count < 2:
return substring
case let count where count == 2:
let decodedArr = substring.hexa2Bytes
let data = Data(decodedArr)
if let decodedStr = String(data: data, encoding: encoding) {
return decodedStr
}
return substring
default: //>2
let thirdSymbolIndex = index(startIndex, offsetBy: 2)
let firstTwo = substring[..<thirdSymbolIndex]
let furhter = substring[thirdSymbolIndex...]
let decodedArr = String(firstTwo).hexa2Bytes
let data = Data(decodedArr)
if let decodedStr = String(data: data, encoding: encoding) {
return decodedStr + furhter
}
return substring
}
}
let result = arr.joined()
return String(encodedPrefix ?? "") + result
}
var hexa2Bytes: [UInt8] {
let hexa = Array(characters)
return stride(from: 0, to: characters.count, by: 2).flatMap { UInt8(String(hexa[$0..<$0.advanced(by: 2)]), radix: 16) }
}
}
A little example which is expected to work with multi-byte string encodings.
extension UInt8 {
//returns 0...15 when '0'...'9', 'A'...'F', 'a'...'f', otherwise returns nil
var hexValue: UInt8? {
if UInt8(ascii: "0") <= self && self <= UInt8(ascii: "9") {
return self - UInt8(ascii: "0")
} else if UInt8(ascii: "A") <= self && self <= UInt8(ascii: "F") {
return self - UInt8(ascii: "A") + 10
} else if UInt8(ascii: "a") <= self && self <= UInt8(ascii: "f") {
return self - UInt8(ascii: "a") + 10
} else {
return nil
}
}
}
extension String {
func removingPercentEncoding(using encoding: String.Encoding) -> String? {
guard let percentEncodedData = self.data(using: encoding) else {return nil}
var byteIterator = percentEncodedData.makeIterator()
var percentDecodedData = Data()
while let b0 = byteIterator.next() {
guard b0 == UInt8(ascii: "%"), let b1 = byteIterator.next() else {
//Non percent character
percentDecodedData.append(b0)
continue
}
guard let h1 = b1.hexValue, let b2 = byteIterator.next() else {
//Keep it as is, when invalid hex-sequece appeared
percentDecodedData.append(b0)
percentDecodedData.append(b1)
continue
}
guard let h2 = b2.hexValue else {
//Keep it as is, when invalid hex-sequece appeared
percentDecodedData.append(b0)
percentDecodedData.append(b1)
percentDecodedData.append(b2)
continue
}
percentDecodedData.append((h1<<4) + h2)
}
return String(data: percentDecodedData, encoding: encoding)
}
}
In my opinion, you should think non-UTF8 percent encoding now is obsolete, and should fix the part which is generating the percent encoded string with CP1251.
let temp: String = "0xffeeffff"
How to convert above String to UInt32, because I need to store it in the bitmap which only accept UInt32
Remove "0x" from your string to convert it to UInt32:
let temp = "0xffeeffff"
let result = UInt32(String(temp.characters.dropFirst(2)), radix: 16)
hope this is help you...
extension String {
func toUInt() -> UInt? {
if contains(self, "-") {
return nil
}
return self.withCString { cptr -> UInt? in
var endPtr : UnsafeMutablePointer<Int8> = nil
errno = 0
let result = strtoul(cptr, &endPtr, 10)
if errno != 0 || endPtr.memory != 0 {
return nil
} else {
return result
}
}
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
How do I check if my string only contains [0-9] and .?
I’d like all other symbols to be deleted from my string.
If a user inputs any String
var anyString:String = “3f00b6r.beAwes0me4me”
I want to extract all the numbers from it (including one . if present) and remove all the other characters.
var myDouble:Double = 3006.04
Someone who know how to do that ?
You can use NSRegularExpression, like this:
// First set up error for checking
var error:NSError?
// Create regular expression pattern to search for numbers one digit in length or longer
let regexString = NSRegularExpression(pattern: "[0-9]{1,}.[0-9]{1,}|[0-9]{1,}", options: nil, error: &error)
// example string
let string = "find the number 10.19"
// get the string length
let strLength = count(string)
// To return the result first of all obtain the range of the first match if there is one, if let used here because NSRegularExpression returns an optional (we could of checked earlier, but I didn't)
if let rangeOfFirstMatch = regexString?.rangeOfFirstMatchInString(string, options: nil, range: NSMakeRange(0, strLength))
{
// if a range has been found that isn't equal to NSNotFound then build a range for the found string
if !NSEqualRanges(rangeOfFirstMatch, NSMakeRange(NSNotFound, 0)) {
advance(string.startIndex, rangeOfFirstMatch.length)
let r = Range(start: advance(string.startIndex, rangeOfFirstMatch.location), end: advance(string.startIndex, rangeOfFirstMatch.location+rangeOfFirstMatch.length))
// return the value
let substringForFirstMatch = string.substringWithRange(r)
println("Here's your match: \(substringForFirstMatch)")
}
}
There's also String.stringByTrimmingCharactersInSet() which would be cleaner and quicker but isn't as versatile. For instance the above string would also be returned if you did this:
let set = NSMutableCharacterSet.alphanumericCharacterSet()
set.addCharactersInString(" ")
set.removeCharactersInString("0123456789.")
string.stringByTrimmingCharactersInSet(set)
But if the string changed to "find the number ??...10.19...." then the stringByTrimmingCharactersInSet() would let you down and return "??...10.19...." while the regular expression version would hold up.
To make things easier a String extension could be written like this for returning multiple numbers in a string of type Double or Int:
extension String {
func stringsMatchingRegularExpression(expression exp:String, error err:NSErrorPointer) -> [String]? {
var strArray:[String]?
var rangeArray:[NSRange]?
let strLength = count(self)
var startOfRange = 0
if let regexString = NSRegularExpression(pattern: exp, options: nil, error: err) {
while startOfRange <= strLength {
let rangeOfMatch = regexString.rangeOfFirstMatchInString(self, options: nil, range: NSMakeRange(startOfRange, strLength-startOfRange))
if let rArray = rangeArray {
rangeArray = rArray + [rangeOfMatch]
}
else {
rangeArray = [rangeOfMatch]
}
startOfRange = rangeOfMatch.location+rangeOfMatch.length
}
if let ranArr = rangeArray {
for r in ranArr {
if !NSEqualRanges(r, NSMakeRange(NSNotFound, 0)) {
advance(self.startIndex, r.length)
let r = Range(start: advance(self.startIndex, r.location), end: advance(string.startIndex, r.location+r.length))
// return the value
let substringForMatch = self.substringWithRange(r)
if let sArray = strArray {
strArray = sArray + [substringForMatch]
}
else {
strArray = [substringForMatch]
}
}
}
}
}
return strArray
}
}
let myString = "one number is 7.5, another is 20"
let subStringArray = myString.stringsMatchingRegularExpression(expression: "[0-9]{1,}.[0-9]{1,}|[0-9]{1,}", error: nil)
subStringArray?[0] // 7.5
subStringArray?[1] // 20
Swift 2.0 Update for Extension
extension String {
func stringsMatchingRegularExpression(expression exp:String) -> [String]? {
var strArray:[String]?
var rangeArray:[NSRange]?
let strLength = self.characters.count
var startOfRange = 0
do {
let regexString = try NSRegularExpression(pattern: exp, options: [])
while startOfRange <= strLength {
let rangeOfMatch = regexString.rangeOfFirstMatchInString(self, options: [], range: NSMakeRange(startOfRange, strLength-startOfRange))
if let rArray = rangeArray {
rangeArray = rArray + [rangeOfMatch]
}
else {
rangeArray = [rangeOfMatch]
}
startOfRange = rangeOfMatch.location+rangeOfMatch.length
}
if let ranArr = rangeArray {
for r in ranArr {
if !NSEqualRanges(r, NSMakeRange(NSNotFound, 0)) {
self.startIndex.advancedBy(r.length)
let r = Range(start: self.startIndex.advancedBy(r.location), end: self.startIndex.advancedBy(r.location + r.length))
// return the value
let substringForMatch = self.substringWithRange(r)
if let sArray = strArray {
strArray = sArray + [substringForMatch]
}
else {
strArray = [substringForMatch]
}
}
}
}
} catch {
}
return strArray
}
}
let myString = "one number is 7.5, another is 20"
let subStringArray = myString.stringsMatchingRegularExpression(expression: "[-+]?\\d+.?\\d+")
subStringArray?[0] // 7.5
subStringArray?[1] // 20
Swift 3.0 Update for Extension
extension String {
func stringsMatchingRegularExpression(expression exp:String) -> [String]? {
var strArray:[String]?
var rangeArray:[NSRange]?
let strLength = self.characters.count
var startOfRange = 0
do {
let regexString = try NSRegularExpression(pattern: exp, options: [])
while startOfRange <= strLength {
let rangeOfMatch = regexString.rangeOfFirstMatch(in: self, options: [], range: NSMakeRange(startOfRange, strLength-startOfRange))
if let rArray = rangeArray {
rangeArray = rArray + [rangeOfMatch]
}
else {
rangeArray = [rangeOfMatch]
}
startOfRange = rangeOfMatch.location+rangeOfMatch.length
}
if let ranArr = rangeArray {
for r in ranArr {
if !NSEqualRanges(r, NSMakeRange(NSNotFound, 0)) {
self.index(startIndex, offsetBy: r.length)
let r = self.index(startIndex, offsetBy:r.location)..<self.index(startIndex, offsetBy:r.location + r.length)
// return the value
let substringForMatch = self.substring(with: r)
if let sArray = strArray {
strArray = sArray + [substringForMatch]
}
else {
strArray = [substringForMatch]
}
}
}
}
}
catch {
// catch errors here
}
return strArray
}
}
let myString = "one number is 7.5, another is 20"
let subStringArray = myString.stringsMatchingRegularExpression(expression: "[-+]?\\d+.?\\d+")
subStringArray?[0] // 7.5
subStringArray?[1] // 20
What is the easiest way to create a word wrap in Swift from a string? Let's say I have a string with 150 characters and I wish to start a new line every 50 characters. Your thoughts are most appreciated.
How about something like this:
extension String {
public func wrap(columns: Int = 80) -> String {
let scanner = NSScanner(string: self)
var result = ""
var currentLineLength = 0
var word: NSString?
while scanner.scanUpToCharactersFromSet(NSMutableCharacterSet.whitespaceAndNewlineCharacterSet(), intoString: &word), let word = word {
let wordLength = word.length
if currentLineLength != 0 && currentLineLength + wordLength + 1 > columns {
// too long for current line, wrap
result += "\n"
currentLineLength = 0
}
// append the word
if currentLineLength != 0 {
result += " "
currentLineLength += 1
}
result += word as String
currentLineLength += wordLength
}
return result
}
}
With tests:
func testWrapSimple() {
let value = "This is a string that wraps!".wrap(10)
XCTAssertEqual(value, "This is a\nstring\nthat\nwraps!")
}
func testWrapLongWords() {
let value = "Thesewordsare toolongforasingle line".wrap(10)
XCTAssertEqual(value, "Thesewordsare\ntoolongforasingle\nline")
}
Here is a crude swift word wrap program. Feel free to comment - because everyday is a school day!
import UIKit
class ViewController: UIViewController {
var string1: String = "I think this is a good word wrap method, but I must try many times!"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let arr = split(string1, { $0 == " "}, maxSplit: Int.max, allowEmptySlices: false)
println(arr)
for words in arr {
println("variable string1 has \(countElements(words)) characters!")
}
var firstThirtyFive: String = string1.substringToIndex(advance(string1.startIndex, 35))
println(firstThirtyFive)
var arr2 = split(firstThirtyFive, { $0 == " "}, maxSplit: Int.max, allowEmptySlices: false)
println(arr2.count)
var removed = arr2.removeLast()
println(arr2)
println(removed)
var fromThirtyFive:String = string1.substringFromIndex(advance(string1.startIndex,35))
println(fromThirtyFive)
var arr3 = split(fromThirtyFive, { $0 == " "}, maxSplit: Int.max, allowEmptySlices: false)
var removeFirst = arr3.removeAtIndex(0)
var newWord:String = removed + removeFirst
println(removeFirst)
println(arr3)
println(newWord)
arr3.insert(newWord, atIndex: 0)
println(arr3)
let res1 = join(" ", arr2)
let res2 = join(" ", arr3)
println(res1)
println(res2)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I notice that when we use SPWeb.GetFile method, we can pass the whole URL or only the part of the url.
Let's say my file exists in servername/sites/SiteA/DocumentLibrary/Folder/file.txt.
(i omit http)
SiteA = servername/sites/SiteA
using (SPWeb oWebsiteFrom = new SPSite(SiteA).OpenWeb())
{
SPFile oSrcSPFile = oWebsiteFrom.GetFile(ServerURL + "/" + DocLibrary+ "/" + Folder + "/" + fileName);
}
This one is also OK to use without ServerURL in GetFile.
using (SPWeb oWebsiteFrom = new SPSite(SiteA).OpenWeb())
{
SPFile oSrcSPFile = oWebsiteFrom.GetFile(DocLibrary+ "/" + Folder + "/" + fileName);
}
What is the difference between using serverURL and not using serverURL in GetFile method?
Basically it is the same.
Lot of SharePoint methods(not all) using Url as parameter will call an internal method named "GetWebRelativeUrlFromUrl" to handle the Url
And below are the code of the methods invoked when you call SPWeb.GetFile
As you can see, the string will parse as UriScheme object and if your string is a ServerRelative uriScheme, the method will "convert" it to absolute url.
internal SPFile GetFile(string strUrl, byte iLevel)
{
string webRelativeUrlFromUrl = this.GetWebRelativeUrlFromUrl(strUrl);
if (webRelativeUrlFromUrl.Length == 0)
{
throw new ArgumentException();
}
return new SPFile(this, webRelativeUrlFromUrl, iLevel);
}
internal string GetWebRelativeUrlFromUrl(string strUrl)
{
return this.GetWebRelativeUrlFromUrl(strUrl, true, true);
}
internal string GetWebRelativeUrlFromUrl(string strUrl, bool includeQueryString, bool canonicalizeUrl)
{
string str;
char[] chrArray;
if (strUrl == null)
{
throw new ArgumentNullException();
}
if (strUrl.Length == 0)
{
return strUrl;
}
if (canonicalizeUrl || !includeQueryString)
{
strUrl = Utility.CanonicalizeFullOrRelativeUrl(strUrl, includeQueryString, out flag);
canonicalizeUrl = 0;
includeQueryString = 1;
}
UriScheme uriScheme = SPWeb.GetUriScheme(strUrl);
if (uriScheme == UriScheme.ServerRelative)
{
string serverRelativeUrl = this.ServerRelativeUrl;
if (!SPUtility.StsStartsWith(strUrl, serverRelativeUrl))
{
throw new ArgumentException();
}
str = strUrl.Substring(serverRelativeUrl.Length);
if (str.Length > 0)
{
if (str.get_Chars(0) == 47)
{
return str.Substring(1);
}
if (uriScheme == UriScheme.Http || uriScheme == UriScheme.Https)
{
if (uriScheme == UriScheme.Http && strUrl.Contains(":80/"))
{
strUrl = strUrl.Remove(strUrl.IndexOf(":80/"), ":80/".Length - 1);
}
bool flag2 = false;
if (!SPUtility.StsStartsWith(strUrl, this.Url))
{
using (SPSite sPSite = new SPSite(strUrl))
{
if (sPSite.ID != this.Site.ID)
{
throw new ArgumentException();
}
UriBuilder uriBuilder = new UriBuilder(new Uri(strUrl));
uriBuilder.Scheme = sPSite.Protocol.TrimEnd(new char[] { 58 });
uriBuilder.Host = sPSite.HostName;
uriBuilder.Port = sPSite.Port;
strUrl = uriBuilder.Uri.ToString();
}
flag2 = SPUtility.StsStartsWith(strUrl, this.Url);
}
else
{
flag2 = true;
}
if (flag2)
{
str = strUrl.Substring(this.Url.Length);
if (str.Length > 0)
{
if (str.get_Chars(0) == 47)
{
return str.Substring(1);
}
throw new ArgumentException();
if (!strUrl.StartsWith("_"))
{
bool flag3 = true;
try
{
if (false || -1 == strUrl.IndexOf(58) || null != new Uri(strUrl))
{
flag3 = false;
}
}
catch
{
}
if (!flag3)
{
throw new ArgumentException();
}
}
str = strUrl;
}
}
}
}
}
return str;
}