This question already has answers here:
How does String substring work in Swift
(25 answers)
How do you use String.substringWithRange? (or, how do Ranges work in Swift?)
(33 answers)
Closed 4 years ago.
How do I substring a string in swift 4.
I would like to convert:
"Hello, World!"
Into:
"Hello"
Swift has no built in function to make this easy so I wrote a simple extension to get the same functionality as other languages such as python which have really easy substring functions.
Extension
Outside your class, add this extension for strings.
extension String {
func substring(start: Int, range: Int) -> String {
let characterArray = Array(self)
var tempArray:[Character] = []
let starting = start
let ending = start + range
for i in (starting...ending) {
tempArray.append(characterArray[i])
}
let finalString = String(tempArray)
return finalString
}
}
Usage
let myString = "Hello, World!"
print(myString.substring(start: 0, range: 4))
This prints:
"Hello"
How It Works
The extension works by turning the string into an array of separate characters then creates a loop which appends the desired characters into a new string which is determined by the function's parameters.
Thanks for stopping by. I hope apple add this basic functionality to their language soon! The above code is a bit messy so if anyone wants to clean it up then feel free!
Related
This question already has answers here:
Partition a string in Rust
(1 answer)
Splitting a UTF-8 string into chunks
(3 answers)
Closed 8 months ago.
Is there any way that I am able to break a string down into smaller substrings of a given length in rust. for e.g. the string is "AAABBBCCC" and we want to break the string down into a vector or array of substrings, for example, the specified length is 3 than we should get a returning array of ["AAA", "BBB", "CCC"]
There are a couple ways this problem can be approached. I assume that since you refer to substrings you want to split it by characters and not bytes. We do not know how many bytes each character occupies in memory so we need to iterate through and check. This makes the process a little more complicated but not by much.
The easiest of which is likely to use the crate itertools since it provides a simple .chunks() function we can use on top of .chars(). I suspect there is a standard library equivalent, but I do not know what it would be.
pub fn to_chunks(string: &str, chunk_size: usize) -> Vec<String> {
let mut sections = Vec::new();
for chunk in &string.chars().chunks(chunk_size) {
sections.push(String::from_iter(chunk))
}
sections
}
Another slightly more performant approach would be to create a Vec of references. Since we can reference the original we do not need to allocate new strings or copy their contents. This can help with performance, however I suspect you are hoping for a Vec<String> so this may or may not be the solution you are looking for. This is one way it could be done with the standard library.
pub fn to_chunks(string: &str, chunk_size: usize) -> Vec<&str> {
let mut sections = Vec::new();
let mut remaining = string;
loop {
// Get the byte offset of the nth character each time so we can split the string
match remaining.char_indices().nth(chunk_size) {
Some((offset, _)) => {
let (a, b) = remaining.split_at(offset);
sections.push(a);
remaining = b;
},
None => {
sections.push(remaining);
return sections
}
}
}
}
This question already has answers here:
How to combine two different length lists in kotlin?
(6 answers)
Closed 1 year ago.
Is there a ready-made solution for creating an list by alternating elements from two list. I understand how this can be done using loops and conditions, but perhaps there is a ready-made extension that will allow you to solve the problem concisely
You can use zip and flatMap result.
val list1 = listOf(1, 2, 3)
val list2 = listOf(4, 5, 6)
val result = list1.zip(list2).flatMap { pair -> listOf(pair.first, pair.second) }
note that this solution executes extra memory allocation for each pair so my recommendation is still to implement your own version.
fun <T> List<T>.mix(other: List<T>): List<T> {
val first = iterator()
val second = other.iterator()
val list = ArrayList<T>(minOf(this.size, other.size))
while (first.hasNext() && second.hasNext()) {
list.add(first.next())
list.add(second.next())
}
return list
}
This question already has answers here:
How do I print my Java object without getting "SomeType#2f92e0f4"?
(13 answers)
Closed 4 years ago.
package MiscellaneousProjects
import java.util.*
class Numbers(val numbers: Int){
}
fun ClosedRange<Int>.random() = Random().nextInt((endInclusive + 1) - start) + start // Function to randomly generate a number
fun main(args: Array<String>) {
var list = arrayListOf<Numbers>()
for(i in 1..10){
val random = Random()
list.add(Numbers((0..100).random())) // Adds the numbers to an array
}
var sortedList = list.sortedWith(compareBy({ it.numbers })) // Sorts the elements from least to greatest
for(element in sortedList){
println(element.numbers) // Prints the individual entries
}
println(sortedList)
}
The following piece of code picks a number from 0 to 100 and adds it to an array.
I am sorting the numbers from greatest to least using sortedWith and compareBy functions. However, when I print "sortedList," the following types of entries are seen: "MiscellaneousProjects.Numbers#30f39991, MiscellaneousProjects.Numbers#452b3a41."
However, whenever I print the individual elements in the array, it outputs the correct numbers.
Can someone tell me the error in my code?
Either use a data class for Numbers (which basically has a built-in toString() that will probably suffice your needs already) or just override toString() yourself in the Numbers class to return the numbers, e.g.
override fun toString() = numbers.toString()
The issue is that you're relying on the default implementation of toString for your Numbers class, which is inherited from Object and prints what you see (i.e., <class_name>#<hash_code>, as you can find here).
To print something more meaningful you can override the toString method (or fun in Kotlin) to return the String you're expecting
I am trying to use the old printf-style string formatters to define a new Swift string from an old Swift string.
I notice this works fine as long as I am starting with a Swift string literal, but not a string variable.
// OK!
String(format:"%s", "hello world".cStringUsingEncoding(NSUTF8StringEncoding))
// ERROR: argument type '[CChar]?' does not conform to expected type 'CVarArgType'
let s = "hello world"
String(format:"%s", s.cStringUsingEncoding(NSUTF8StringEncoding))
Why does this happen?
And what's the best workaround?
(Please note that I am aware of but do not want to use the Cocoa string formatter %#. I want the printf-style formatting code because what I'm actually trying to do is get quick and dirty tabular alignment with codes like %-10s.)
This question concerns Swift 2.2.
Don't create a C string just for alignment. There is a method stringByPaddingToLength for that.
// Swift 2
s.stringByPaddingToLength(10, withString: " ", startingAtIndex: 0)
// Swift 3
s.padding(toLength: 10, withPad: " ", startingAt: 0)
Note that it will truncate the string if it is longer than 10 UTF-16 code units.
The problem here is, there are two methods in Swift named cStringUsingEncoding:
func cStringUsingEncoding(encoding: UInt) -> UnsafePointer<Int8>, as a method of NSString
func cStringUsingEncoding(encoding: NSStringEncoding) -> [CChar]?, as an extension of String
If we want a pointer, we need to ensure we are using an NSString, not a String.
In the first example, a string literal can be a String or NSString, so the compiler chooses NSString since the other one won't work.
But in the second example, the type of s is already set to String, so the method that returns [CChar]? is chosen.
This could be worked-around by forcing s to be an NSString:
let s: NSString = "hello world"
String(format:"%s", s.cStringUsingEncoding(NSUTF8StringEncoding))
kennytm's answer is clearly the best way.
But for anyone else who is still wondering about how to do it the wrong way, and get access to a c string based on a Swift String without going through NSString, this also seems to work (Swift 2.2):
var s:String = "dynamic string"
s.nulTerminatedUTF8.withUnsafeBufferPointer { (buffptr) -> String in
let retval:String = String(format:"%s",buffptr.baseAddress)
return retval
}
I need to edit the pixels' raw binary values of an image. For this, I did this steps:
I obtained the CFData containing the hex dump of the image.
I converted the CFData obtained to an array of characters (using convertToArray function)
After that, I used convertToBinaryString function to obtain a string representing the base 2 value of the hex dump.
It does work and does the job for small files but when it comes to bigger ones it takes forever to finish. I failed in the struggle of finding a faster way. Could you help me?
Down here you can take a look of the functions I need to optimize:
func convertToArray(imageData : CFData) -> Array<Character>{
let arrayData : Array<Character> = Array(String(NSData(data: imageData)).characters)
print("Array : ")
Swift.print(arrayData)
return arrayData
}
func convertToBinaryString(array : Array<Character>) -> String{
let numberOfChars = array.count
var binaryString = convertHexToBinary(array[1])
for character in 2...numberOfChars - 2{
binaryString = binaryString + convertHexToBinary(array[character])
}
// print("BINARRY ARRAY : ")
// print(binaryString)
return binaryString
}
I would try this extension to NSData that provides a CollectionType interface. It seems like it would make it much easier for you to do your modifications without having to much around with UnsafeMutablePointer:
Bytes collection for NSData
Since BytesView and MutableBytesView are a CollectionType it gives you subscripting, indices, and more so you can iterate through your data and make the changes you want.
The article which is relevant to this question and introduces that linked code:
NSData, My Old Friend