Here's what I am trying to do :
let courseName = "Bachelor of Tourism Administration(B.T.A)".condensedWhitespace
let upperCaseCourseName = courseName.uppercaseString
let extrctCourseName = upperCaseCourseName.componentsSeparatedByString(" ").reduce("") { $0.0 + String($0.1.characters.first!) }
let upperCasecourseFirstCharcters = extrctCourseName
print(upperCasecourseFirstCharcters) // output : "BOTA" but i want "BTA"
as you see that my outPut of "Bachelor of Tourism Administration(B.T.A)" is BOTA but the desired output is BTA because word of is starting from a lowerCase and i want to ignore that word in my this method , how am gonna do that any idea ?
let courseName = "Bachelor of Tourism Administration(B.T.A)" //.condensedWhitespace
var newString = ""
let array : NSArray = courseName.componentsSeparatedByString(" ")
for chr in array {
let str = chr as! NSString
if str.lowercaseString != str{
if newString.characters.count > 0{
newString = newString.stringByAppendingString(" "+(str as String))
continue
}
newString = newString.stringByAppendingString((str as String))
}
}
let upperCaseCourseName = newString.uppercaseString
let extrctCourseName = upperCaseCourseName.componentsSeparatedByString(" ").reduce("") { $0.0 + String($0.1.characters.first!) }
let upperCasecourseFirstCharcters = extrctCourseName
print(upperCasecourseFirstCharcters)
//This will defiantly meet to your problem/. Let me know if it works for u or not
You can paste this into a playground:
extension String {
func array() -> [String] {
return self.componentsSeparatedByString(" ")
}
func abbreviate() -> String {
var output = ""
let array = self.array()
for word in array {
let index = word.startIndex.advancedBy(0)
let str = String(word[index])
if str.lowercaseString != str {
output += str
}
}
return output
}
}
let courseName = "Bachelor of Tourism Administration(B.T.A)".abbreviate()
print(courseName) // prints BTA
A clean approach would be:
extension Character
{
public func isUpper() -> Bool
{
let characterString = String(self)
return (characterString == characterString.uppercaseString) && (characterString != characterString.lowercaseString)
}
}
let courseName = "Bachelor of Tourism Administration(B.T.A)"
let upperCaseCourseName = courseName
let extrctCourseName = upperCaseCourseName.componentsSeparatedByString(" ").reduce("") {
if($0.1.characters.first!.isUpper()) {
return $0.0 + String($0.1.characters.first!)
}else {
return $0.0
}
}
Related
I have React Native project. And I need in the native part of IOS to make string interpolation of formattedValue with a character, but I get the error "Type of expression is ambiguous without more context", and if I try the same code in the playground everything is working with out error. I'm not so experienced in SWIFT, can you tell me please why I get this error? And which the best way to make a string interpolation?
import Foundation
import SciChart.Protected.SCILabelProviderBase
class SCIAxisNumericLabelProvider: SCILabelProviderBase<ISCINumericAxis> {
var format: String?
var specialChar: String?
init(format: String?) {
let pattern = "[^0-9.]"
let regex = try! NSRegularExpression(pattern: pattern)
let formatValue = regex.stringByReplacingMatches(in: format ?? "", range: NSMakeRange(0, format?.count ?? 0), withTemplate: "")
self.format = formatValue
self.specialChar = format?.replacingOccurrences(of: "\(formatValue)", with: "")
super.init(axisType: ISCINumericAxis.self)
}
override func formatLabel(_ dataValue: ISCIComparable!) -> ISCIString! {
let dataValueToDouble = dataValue.toDouble()
let formattedValue = NSString(format: NSString(string: self.toFormat()), dataValueToDouble == -0 ? 0 : dataValueToDouble)
if let char = specialChar {
return "\(formattedValue) \(NSString(char))" // Here I get the error Type of expression is ambiguous without more context
}
return formattedValue
}
override func formatCursorLabel(_ dataValue: ISCIComparable!) -> ISCIString! {
return formatLabel(dataValue)
}
func toFormat() -> String {
if (self.format != nil) {
let a = self.format!.split(separator: ".")
if (a.count > 1) {
return "%0." + String(a[1].count) + "f"
}
}
return "%0.f"
}
func extractSpecialChar(value: String) {
}
}
In the end of the day I decided this error, I separated string interpolation and converting:
override func formatLabel(_ dataValue: ISCIComparable!) -> ISCIString! {
let formatterValue = self.toFormat();
let valueDouble = dataValue.toDouble()
let valueDoubleExcludedNegZero = valueDouble == -0 ? 0 : valueDouble
let precisionString = String(format: formatterValue, valueDoubleExcludedNegZero)
if let char = specialChar {
let resultString = precisionString + " " + char
return NSString(string: resultString)
}
return NSString(string: precisionString)
}
This is my code so far, with no errors, but it is not picking the dates from the 5 day forecast. What is wrong in this code?
//: to display the 5 day date array from the open weather API
enter code herevar temperatureArray: Array = Array()
var dayNumber = 0
var readingNumber = 0
if let jsonObj = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? NSDictionary {
if let mainArray = jsonObj!.value(forKey: "list") as? NSArray {
for dict in mainArray {
if let mainDictionary = (dict as! NSDictionary).value(forKey: "main") as? NSDictionary {
if let temperature = mainDictionary.value(forKey: "temp_max") as? Double {
if readingNumber == 0 {
temperatureArray.append(temperature)
} else if temperature > temperatureArray[dayNumber] {
temperatureArray[dayNumber] = temperature
}
} else {
print("Error: unable to find temperature in dictionary")
}
} else {
print("Error: unable to find main dictionary")
}
readingNumber += 1
if readingNumber == 8 {
readingNumber = 0
dayNumber += 1
}
var dateArray: Array<String> = Array()
var dayNumber = 0
var readingNumber = 0
if let weatherArray = jsonObj!.value(forKey: "list") as? NSArray {
for dict in weatherArray {
if let weatherDictionary = (dict as! NSDictionary).value(forKey: "list") as? NSDictionary {
if let date = weatherDictionary.value(forKey: "dt_txt") as? String {
if readingNumber == 0 {
dateArray.append(date)
} else if date > dateArray[dayNumber] {
dateArray[dayNumber] = date
}
}
} else {
print("Error: unable to find date in dictionary")
}
readingNumber += 1
if readingNumber == 8 {
readingNumber = 0
dayNumber += 1
}
}
}
}
}
}
func fixTempForDisplay(temp: Double) -> String {
let temperature = round(temp)
let temperatureString = String(format: "%.0f", temperature)
return temperatureString
}
DispatchQueue.main.async {
self.weatherLabel1.text = "Today: (fixTempForDisplay(temp: temperatureArray[0]))°C"
self.weatherLabel2.text = "Tomorrow: (fixTempForDisplay(temp: temperatureArray[1]))°C"
self.weatherLabel3.text = "Day 3: (fixTempForDisplay(temp: temperatureArray[2]))°C"
self.weatherLabel4.text = "Day 4: (fixTempForDisplay(temp: temperatureArray[3]))°C"
self.weatherLabel5.text = "Day 5: (fixTempForDisplay(temp: temperatureArray[4]))°C"
func formatDate(date: NSDate) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
return dateFormatter.string(from: date as Date)
}
self.dateLabel1.text = ": \(formatDate(date: dateArray[0]))"
self.dateLabel2.text = ": \(formatDate(date: dateArray[1]))"
self.dateLabel3.text = ": \(formatDate(date: dateArray[2]))"
self.dateLabel4.text = ": \(formatDate(date: dateArray[3]))"
self.dateLabel5.text = ": \(formatDate(date: dateArray[4]))"
}
}
}
dataTask.resume()
}
}
It looks to me like you need to change your icon array to contain strings
var iconArray: Array<String> = Array()
and then when parsing the json text
if let icon = weatherDictionary.value(forKey: "icon") as? String {
and finally
self.iconImage1.image = UIImage(named: iconArray[0])
self.iconImage2.image = UIImage(named: iconArray[1])
Of course the below comparison won't work anymore when icon is a string but I don't understand any of this if/else clasue so I don't know what to replace it with
if readingNumber == 0 {
iconArray.append(icon)
} else if icon > iconArray[dayNumber] { //This won't work now.
iconArray[dayNumber] = icon
}
I am currently filtering using
self.searchArray.removeAll(keepCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (Array(exampleArray) as NSArray).filteredArrayUsingPredicate(searchPredicate)
self.searchArray = array as! [String]
It is filtering the whole string, However, I only want to filter using all characters that exist before my delimiter. For example:
each array value has a delimiter which is "$%^"
example array contains [abc$%^12], [efg$%^32], [tyh$%^77]
I only want the filtering to include on all characters before $%^ which would be abc, efg, and tyh
You can do this without using NSPredicate. Stub:
let searchBarText = "h"
let exampleArray = ["abc$%^12", "efg$%^32", "tyh$%^77"]
let searchResults = exampleArray.filter {
let components = $0.componentsSeparatedByString("$%^")
return components[0].containsString(searchBarText)
}
'pure' Swift solution :-) (I don't like any help of Foundation)
let arr = ["abc$%^12", "efg$%^32", "tyh$%^77", "nodelemiter"]
let delimiter = "$%^"
func splitByDelimeter(let str: String, delimiter: String)->(String,String) {
var str1 = ""
var str2 = str
while !str2.hasPrefix(delimiter) && str2.characters.count > 0 {
str1.append(str2.removeAtIndex(str2.startIndex))
}
if (str1 == str) { return (str1, "") }
let r = Range(start: str2.startIndex, end: str2.startIndex.advancedBy(delimiter.characters.count))
str2.removeRange(r)
return (str1, str2)
}
let res = arr.map { splitByDelimeter($0, delimiter: delimiter).0 }
print(res) // ["abc", "efg", "tyh", "nodelemiter"]
let res2 = arr.map { splitByDelimeter($0, delimiter: delimiter) }
print(res2) // [("abc", "12"), ("efg", "32"), ("tyh", "77"), ("nodelemiter", "")]
it should work, even there is only delimiter, or more than one delimiter in your string. First occurrence of delimiter will split the string to two parts.
UPDATE
with help of String extension you can do it as ...
let arr = ["abc$%^12", "efg$%^32", "tyh$%^77", "nodelemiter", "$%^jhdk$%^jdhjahsd", "22lemar$%^fralemdo"]
extension String {
func splitBy(delimiter: String)->(String,String) {
var str1 = ""
var str2 = self
while !str2.hasPrefix(delimiter) && str2.characters.count > 0 {
str1.append(str2.removeAtIndex(str2.startIndex))
}
if (str1 == self) { return (str1, "") }
let r = Range(start: str2.startIndex, end: str2.startIndex.advancedBy(delimiter.characters.count))
str2.removeRange(r)
return (str1, str2)
}
func contains(string: String)->Bool {
guard !self.isEmpty else {
return false
}
var s = self.characters.map{ $0 }
let c = string.characters.map{ $0 }
repeat {
if s.startsWith(c){
return true
} else {
s.removeFirst()
}
} while s.count > c.count - 1
return false
}
}
let filtered = arr.map{ $0.splitBy("$%^").0 }.filter { $0.contains("lem") }
print(filtered) // ["nodelemiter", "22lemar"]
or you can use hasPrefix to narrow search by typing more chars to you search box ... etc.
let arr2 = ["abc$%^12", "abefg$%^32", "tyhab$%^77"]
let filtered2 = arr2.map{ $0.splitBy("$%^").0 }.filter { $0.hasPrefix("ab") }
print(filtered2) // ["abc", "abefg"]
I am trying to trim a phone number and using the following code but it does not trim whitespace or the '-'. I need to erase all chars except those in the character set given
func trimmedNumber(s : String)->String
{
let characterSet = NSCharacterSet(charactersInString: "+*#0123456789")
let trimmedString = s.stringByTrimmingCharactersInSet(characterSet.invertedSet)
return trimmedString
}
Swift 3/4:
let set = CharacterSet(charactersIn: "+*#0123456789")
let stripped = s.components(separatedBy: set.inverted).joined()
func trimmedNumber(s : String) -> String {
let characterSet = Set("+*#0123456789".characters)
return String(s.characters.lazy.filter(characterSet.contains))
}
Or in Swift 1:
func trimmedNumber(s : String) -> String {
let characterSet = Set("+*#0123456789")
return String(lazy(s).filter { characterSet.contains($0) })
}
Add the method removingCharacters(in:) to Swift's String type. It returns a new string made by removing the characters in a given character set from the String.
For example:
let string = "+1-202-555-0141"
let set = CharacterSet(charactersIn: "+*#0123456789")
let sanitized = string.removingCharacters(in: set.inverted)
// sanitized is equal to "+12025550141"
Helpers.swift
extension String {
public func removingCharacters(in set: CharacterSet) -> String {
let filtered = unicodeScalars.filter { !set.contains($0) }
return String(String.UnicodeScalarView(filtered))
}
}
HelpersTests.swift
import XCTest
class HelpersTests: XCTestCase {
func testRemovingCharacters() {
let inputText1 = ""
let set1 = CharacterSet.decimalDigits.inverted
let sanitized1 = inputText1.removingCharacters(in: set1)
XCTAssertEqual("", sanitized1)
let inputText2 = " tab:\tspace: no-break_space: "
let set2 = CharacterSet.whitespaces
let sanitized2 = inputText2.removingCharacters(in: set2)
XCTAssertEqual("tab:space:no-break_space:", sanitized2)
let inputText3 = " aBc!##12 $%^&*()-_=+[{]}\\|;:'\"3,<.>/?`~ "
let set3 = CharacterSet.alphanumerics.inverted
let sanitized3 = inputText3.removingCharacters(in: set3)
XCTAssertEqual("aBc123", sanitized3)
}
}
See also: Convert Array of UnicodeScalar into String in Swift
works in swift 1&2
let s = "adasdad+3124124+r323*4asdasdbk*($&##"
let characterSet = NSCharacterSet(charactersInString: "+*#0123456789").invertedSet;
let elements = s.componentsSeparatedByCharactersInSet(characterSet)
let filtered = (elements as NSArray).componentsJoinedByString("")
print(filtered);
I am trying to duplicate Need to write calculator in Objective-C in Swift but my code is not working.
import Foundation
var equation:NSString = "5*(2.56-1.79)-4.1"
var result = NSExpression(format: equation, argumentArray: nil)
println(result)
As already said in a comment, you have to call expressionValueWithObject()
on the expression:
let expr = NSExpression(format: equation)
if let result = expr.expressionValueWithObject(nil, context: nil) as? NSNumber {
let x = result.doubleValue
println(x)
} else {
println("failed")
}
Update for Swift 3:
let expr = NSExpression(format: equation)
if let result = expr.expressionValue(with: nil, context: nil) as? Double {
print(result) // -0.25
} else {
print("failed")
}
Details
Xcode 9.4.1, Swift 4.1
Xcode 10.2.1 (10E1001), Swift 5
Solution
import Foundation
extension String {
private func allNumsToDouble() -> String {
let symbolsCharSet = ".,"
let fullCharSet = "0123456789" + symbolsCharSet
var i = 0
var result = ""
var chars = Array(self)
while i < chars.count {
if fullCharSet.contains(chars[i]) {
var numString = String(chars[i])
i += 1
loop: while i < chars.count {
if fullCharSet.contains(chars[i]) {
numString += String(chars[i])
i += 1
} else {
break loop
}
}
if let num = Double(numString) {
result += "\(num)"
} else {
result += numString
}
} else {
result += String(chars[i])
i += 1
}
}
return result
}
func calculate() -> Double? {
let transformedString = allNumsToDouble()
let expr = NSExpression(format: transformedString)
return expr.expressionValue(with: nil, context: nil) as? Double
}
}
Usage
"3*(3-1)-5".calculate()
Full sample
func test(_ expressrion: String) {
if let num = expressrion.calculate() {
print("\(expressrion) = \(num)")
} else {
print("\(expressrion) = nil")
}
}
test("3*(3-1)-5")
test("5.2*(2-1.79)-5.1")
test("11/5")
Results