Why modifying a String in Go is NOT allocating extra space? - string

I'm new to Go and trying to understand how Strings work in Go. My major doubt is, why changing str from "black" to "Orange" in my example NOT change the address of str. I notice the address changes while making a copy with str_cpy.
Thanks in advance.
Code:
func main(){
// set str as Black
var str string = "Black"
log.Println("String is set to: ", str)
log.Println("Current address of String is: ", &str)
//set str as black
log.Println("Testing Mutability...")
slice := []rune(str)
slice[0] = 'b'
str = string(slice)
log.Println("String after mutation is...", str)
log.Println("Current address of String is: ", &str)
//make a copy of str, str_cpy expected value: black
str_cpy := str
log.Println("StringCOPY is set to: ", str_cpy)
log.Println("Current address of StringCOPY is: ", &str_cpy)
//change str from black to Orange
str = "Orange"
log.Println("String now is...", str)
log.Println("Current address of String is: ", &str)
changeusingPointer(&str)
log.Println("String was changed using pointer to: ", str)
log.Println("Current address of String is: ", &str)
}
func changeusingPointer(s *string){
log.Println("s points to ", s)
*s = "White"
}
The Output I get is:
2023/02/18 10:39:38 String is set to: Black
2023/02/18 10:39:38 Current address of String is: 0xc000014060
2023/02/18 10:39:38 Testing Mutability...
2023/02/18 10:39:38 String after mutation is... black
2023/02/18 10:39:38 Current address of String is: 0xc000014060
2023/02/18 10:39:38 StringCOPY is set to: black
2023/02/18 10:39:38 Current address of StringCOPY is: 0xc000014090
2023/02/18 10:39:38 String now is... Orange
2023/02/18 10:39:38 Current address of String is: 0xc000014060
2023/02/18 10:39:38 s points to 0xc000014060
2023/02/18 10:39:38 String was changed using pointer to: White
2023/02/18 10:39:38 Current address of String is: 0xc000014060
I expected the address of string str to change while changing its value from "black" to "Orange" .

A string is a structure containing two elements: pointer to the array containing the string, and the string length. So when you declare str="Orange", what happens resembles the following:
str=internalString{ arr: <pointer to array "Orange">, len: 6}
When you assign a new value to str, like "Black", this becomes:
str=internalString{ arr: <pointer to array "Black">, len: 5}
Address of str does not change.

when you create str_copy you copy the value and put it some where else so the pointer should change but when you change the value of str the array pointer remains constant just the values change

Related

How do I make the fill padding in std::format dynamic?

To create a format output and pad your output with n you can do something like this in rust:
fn main() {
let title = " Title ";
println!("┌{:─^11}┐", title);
}
That will print:
┌── Title ──┐
So the str is padded (centered via ^) on both sides with - within the space of 11 characters.
How can I make this width dynamic though? Via a variable.
So turns out that's a built-in functionality. std::format comes with a width option indicated with a postfix $.
fn main() {
let title = " Title ";
println!("┌{:─^width$}┐", title, width = 11);
}
This will print:
┌── Title ──┐
https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5666cd7f274d436e2216e7ecd0320072

How do I convert number to a specific format?

I want to know if there a way to apply custom masking/format to string and get the output
number:= 12345678
I want to format my number to a specific format.
func formatNumber(number string) string {
format:= 123-45 678
// do something here to format number
return formatedNumber
}
There are a few misconceptions in your code sample. Numbers in a computer aren't formatted, but a string representation of a number can be. Example below.
func main() {
n1 := 12345678 // type = int
fmt.Printf("type: %T, value: %d\n", n1, n1) // outputs "type: int, value: 12345678"
n2 := "12345678" // type = string
fmt.Printf("type: %T, value: %s\n", n2, n2) // outputs "type: string, value: 12345678"
}
See https://golang.org/pkg/fmt/ for where %T and %d and %s come from.
To format a number, I don't think you can get exactly what you want. A few options though:
turn an int to a string: mystring := fmt.Sprintf("%d", myint)
If you already have a string, take substrings and then add additional formatting characters in your format output.
Below gets you something like what you seem to want based on your question.
func main() {
mynumber := 12345678
mystring := fmt.Sprintf("%d", mynumber)
myformattedstring := fmt.Sprintf("%s-%s %s", mystring[:3], mystring[3:5], mystring[5:])
fmt.Println(myformattedstring)
}
Here is a playground with this code.
Use math to calculate a number for each position. Format those numbers using fmt.Sprintf:
func formatNumber(number string) string {
return fmt.Sprintf("%03d-%02d %03d",
number/100000, (number%100000)/1000,
number%1000)
}
A feature of this answered compared to others is that it correctly handles numbers less than 10000000.

Get String Between 2 Strings with Arduino

I am looking for a way to get a String between 2 Strings using Arduino. This is the source String:
Hello, my name is John Doe# and my favourite number is 32#.
The output has to be:
String name = "John Doe"; //Between "name is " and "#"
String favouriteNumber = "32"; //Between "number is " and "#"
How can this be achieved with Arduino?
I am not able to find any information online about this. Those examples for C are not working anyway. I understand that using String is not recommended in Arduino, but I have to do it this way to make things simpler.
By the way, this method of using a '#' to indicate the end of the data is not an ideal way to do it as I would like the input to be more human readable and more natural. Would anyone please suggest another way to do this as well?
Thanks in advance!
Function midString find the substring that is between two other strings "start" and "finish". If such a string does not exist, it returns "". A test code is included too.
void setup() {
test();
}
void loop() {
delay(100);
}
String midString(String str, String start, String finish){
int locStart = str.indexOf(start);
if (locStart==-1) return "";
locStart += start.length();
int locFinish = str.indexOf(finish, locStart);
if (locFinish==-1) return "";
return str.substring(locStart, locFinish);
}
void test(){
Serial.begin(115200);
String str = "Get a substring of a String. The starting index is inclusive (the corresponding character is included in the substring), but the optional ending index is exclusive";
Serial.print(">");
Serial.print( midString( str, "substring", "String" ) );
Serial.println("<");
Serial.print(">");
Serial.print( midString( str, "substring", "." ) );
Serial.println("<");
Serial.print(">");
Serial.print( midString( str, "corresponding", "inclusive" ) );
Serial.println("<");
Serial.print(">");
Serial.print( midString( str, "object", "inclusive" ) );
Serial.println("<");
}
just searched for this and saw no answer so i cooked one up.
i prefer working with String as well because of code readability and simplicity.
for me its more important than squeezing every last drop of juice out of my arduino.
String name = GetStringBetweenStrings("Hello, my name is John Doe# and my favourite number is 32#." ,"name is ","#");
String GetStringBetweenStrings(String input, String firstdel, String enddel){
int posfrom = input.indexOf(firstdel) + firstdel.length();
int posto = input.indexOf(enddel);
return input.substring(posfrom, posto);
}
watch out for the first case its fine, but for the second one you would have to change the second filter sting to "#." so it doesn't use the first occurrence of the #

How to convert NSString to Character in Swift?

I want to convert NSString to Character in Swift.
I am getting a String from NSTextField, where I input a single character (Example "#"), I need this in Character type.
Use Character class
var chars = [Character](str)
this should be as simple as let characterFromString = Character(textField.text).
NSString is automatically bridged to Swift's String, and the Character class has an init which accepts a single character String; see the documentation here.
This requires that the input string contain a single grapheme cluster (i.e. a single character) and so you might want to validate your input before casting. A slightly more verbose version of the above would be:
let text = textField.text as String
if countElements(text) == 1 {
let character = Character(text)
// do what you want
} else {
// bad input :-(
}
The stringValue of NSTextField actually returns a Swift string and not NSString:
let str = myTextField.stringValue // str is a String
You get the first element with
let ch = str[str.startIndex] // ch is a Character
A NSString would have to be converted to a Swift string first:
let nsString : NSString = "#"
let str = String(nsString)
let ch = str[str.startIndex]

How to calculate the target string in a UITextFieldDelegate method?

Problem
In UITextFieldDelegate's textField:shouldChangeCharactersInRange:replacementString we are given the original text in tf.text, the replacement string, and the range.
This is sufficient information to calculate the target string (what the TextField would contain if we didn't intercept), but I'm having trouble getting this code to compile:
func textField(
tf: UITextField,
shouldChangeCharactersInRange range: NSRange,
replacementString str: String
) -> Bool
{
var tgt = String( tf.text )
tgt.replaceRange( range.toRange(), with: str ) // PROBLEM HERE
NSLog( "realtime: %#", tgt )
return true
}
The problem I seem to be having is, String's replaceRange:with: takes a character, not a String.
Perhaps there is a better or easier approach to calculate tgt?
You can do this if you use NSStrings methods. Change the first line of your method to declare an NSMutableString instead of a String:
func textField(tf: UITextField, shouldChangeCharactersInRange range: NSRange,
replacementString str: String) -> Bool {
var tgt = NSMutableString()
tgt.appendString( tf.text )
tgt.replaceCharactersInRange( range, withString: str )
NSLog( "realtime: %#", tgt )
return true
}
(The problem stems from NSRange and built-in Swift Range instances not being compatible for strings.)

Resources