How to convert number (int or float64) to string in Golang - string

How do I convert any given number which can be a int or float64 to string ?
Using strconv.FormatFloat or FormatInt I have to specify that the given number is a float or integer.
In my case it is unknown what I get.
Behaviour:
When I get a 5 it should be converted into "5" and not "5.00"
When I get a 1.23 it should be converted into "1.23" and not "1"

You may use fmt.Sprint
fmt.Sprint returns string format of any variable passed to it
Sample
package main
import (
"fmt"
)
func main() {
f := fmt.Sprint(5.03)
i := fmt.Sprint(5)
fmt.Println("float:",f,"\nint:",i)
}
play link

If you don't know what type the number you need to convert to string will be, you can just use fmt.Sprintf with the %v verb:
fmt.Sprintf("%v", 1.23) // "1.23"
fmt.Sprintf("%v", 5) // "5"

Related

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.

Appending integer to a string by casting and using the concatenation operator

I am trying to concatenate an integer with an existing string by casting and the appending using +. But it doesn't work.
package main
import (
"fmt"
)
func main() {
a := 4
b := "The value of a is "
fmt.Println(b + string(a))
}
This prints a garbage character on go playground and nothing on the Unix terminal. What could be the reason for this? What is incorrect with this method?
From the Go language spec:
Converting a signed or unsigned integer value to a string type yields a string containing the UTF-8 representation of the integer.
In order to achieve the desired result, you need to convert your int to a string using a method like strconv.Itoa:
package main
import (
"fmt"
"strconv"
)
func main() {
a := 4
b := "The value of a is "
fmt.Println(b + strconv.Itoa(a))
}
Use fmt.Sprintf or Printf; no casting required:
fmt.Sprintf("%s%d",s,i)

Go convert int64 (from UnixNano) to location time string

I have an int64 like:
1502712864232
Which is the result of a REST GET to a service. I can convert it to a string easily enough. It is a Unixnano timestamp.
What I really need is to convert it to a string which is related to a timezone like "Europe/London". Such as:-
"14/08/2017, 13:14:24"
Such as produced by this handy utility:
http://www.freeformatter.com/epoch-timestamp-to-date-converter.html
Would very much appreciate any assistance.
==> Update.
Thanks to #evanmcdonnal for such a useful answer. Much appreciated.
Turns out that the data I had was not UnixNano at all (sorry) it was milliseconds from Epoch. Source is a Jenkins timestamp....
So... I wrote the following helper function to get what I need:
// Arg 1 is an int64 representing the millis since Epoch
// Arg 2 is a timezome. Eg: "Europe/London"
// Arg 3 is an int relating to the formatting of the returned string
// Needs the time package. Obviously.
func getFormattedTimeFromEpochMillis(z int64, zone string, style int) string {
var x string
secondsSinceEpoch := z / 1000
unixTime := time.Unix(secondsSinceEpoch, 0)
timeZoneLocation, err := time.LoadLocation(zone)
if err != nil {
fmt.Println("Error loading timezone:", err)
}
timeInZone := unixTime.In(timeZoneLocation)
switch style {
case 1:
timeInZoneStyleOne := timeInZone.Format("Mon Jan 2 15:04:05")
//Mon Aug 14 13:36:02
return timeInZoneStyleOne
case 2:
timeInZoneStyleTwo := timeInZone.Format("02-01-2006 15:04:05")
//14-08-2017 13:36:02
return timeInZoneStyleTwo
case 3:
timeInZoneStyleThree := timeInZone.Format("2006-02-01 15:04:05")
//2017-14-08 13:36:02
return timeInZoneStyleThree
}
return x
}
Rather than converting this to a string, you'll want to convert it to a time.Time and from there to a string. You can use the handy Unix method to get a Time object back for that time stamp.
import "time"
import "fmt"
t := time.Unix(0, 1502712864232)
fmt.Println(t.Format("02/01/2006, 15:04:05"))
Edit: added format to the println - note, testing your unix stamp in go playground, that value is neither nano seconds nor seconds, in both cases the time value produced is way off of what it should be. The code above still demonstrates the basic idea of what you want to do but it seems an additional step is necessary or the sample int64 you gave just does not correspond to the string you provided.
relevant docs:
https://golang.org/pkg/time/#Unix
https://golang.org/pkg/fmt/

How to convert []int8 to string

What's the best way (fastest performance) to convert from []int8 to string?
For []byte we could do string(byteslice), but for []int8 it gives an error:
cannot convert ba (type []int8) to type string
I got the ba from SliceScan() method of *sqlx.Rows that produces []int8 instead of string
Is this solution the fastest?
func B2S(bs []int8) string {
ba := []byte{}
for _, b := range bs {
ba = append(ba, byte(b))
}
return string(ba)
}
EDIT my bad, it's uint8 instead of int8.. so I can do string(ba) directly.
Note beforehand: The asker first stated that input slice is []int8 so that is what the answer is for. Later he realized the input is []uint8 which can be directly converted to string because byte is an alias for uint8 (and []byte => string conversion is supported by the language spec).
You can't convert slices of different types, you have to do it manually.
Question is what type of slice should we convert to? We have 2 candidates: []byte and []rune. Strings are stored as UTF-8 encoded byte sequences internally ([]byte), and a string can also be converted to a slice of runes. The language supports converting both of these types ([]byte and []rune) to string.
A rune is a unicode codepoint. And if we try to convert an int8 to a rune in a one-to-one fashion, it will fail (meaning wrong output) if the input contains characters which are encoded to multiple bytes (using UTF-8) because in this case multiple int8 values should end up in one rune.
Let's start from the string "世界" whose bytes are:
fmt.Println([]byte("世界"))
// Output: [228 184 150 231 149 140]
And its runes:
fmt.Println([]rune("世界"))
// [19990 30028]
It's only 2 runes and 6 bytes. So obviously 1-to-1 int8->rune mapping won't work, we have to go with 1-1 int8->byte mapping.
byte is alias for uint8 having range 0..255, to convert it to []int8 (having range -128..127) we have to use -256+bytevalue if the byte value is > 127 so the "世界" string in []int8 looks like this:
[-28 -72 -106 -25 -107 -116]
The backward conversion what we want is: bytevalue = 256 + int8value if the int8 is negative but we can't do this as int8 (range -128..127) and neither as byte (range 0..255) so we also have to convert it to int first (and back to byte at the end). This could look something like this:
if v < 0 {
b[i] = byte(256 + int(v))
} else {
b[i] = byte(v)
}
But actually since signed integers are represented using 2's complement, we get the same result if we simply use a byte(v) conversion (which in case of negative numbers this is equivalent to 256 + v).
Note: Since we know the length of the slice, it is much faster to allocate a slice with this length and just set its elements using indexing [] and not calling the built-in append function.
So here is the final conversion:
func B2S(bs []int8) string {
b := make([]byte, len(bs))
for i, v := range bs {
b[i] = byte(v)
}
return string(b)
}
Try it on the Go Playground.
Not entirely sure it is the fastest, but I haven't found anything better.
Change ba := []byte{} for ba := make([]byte,0, len(bs) so at the end you have:
func B2S(bs []int8) string {
ba := make([]byte,0, len(bs))
for _, b := range bs {
ba = append(ba, byte(b))
}
return string(ba)
}
This way the append function will never try to insert more data that it can fit in the slice's underlying array and you will avoid unnecessary copying to a bigger array.
What is sure from "Convert between slices of different types" is that you have to build the right slice from your original int8[].
I ended up using rune (int32 alias) (playground), assuming that the uint8 were all simple ascii character. That is obviously an over-simplification and icza's answer has more on that.
Plus the SliceScan() method ended up returning uint8[] anyway.
package main
import (
"fmt"
)
func main() {
s := []int8{'a', 'b', 'c'}
b := make([]rune, len(s))
for i, v := range s {
b[i] = rune(v)
}
fmt.Println(string(b))
}
But I didn't benchmark it against using a []byte.
Use unsafe package.
func B2S(bs []int8) string {
return strings.TrimRight(string(*(*[]byte)unsafe.Pointer(&bs)), "\x00")
}
Send again ^^

Arduino: String to int gets strange values

I want to convert a String to an int, and all I could find is that you have to convert the String to a char array and then cast this array to an int, but my code produces strange values and I can't figure out what the problem is.
void ledDimm(String command)
{
// Get the Value xx from string LEDDimm=xx
String substring = command.substring(8, command.length());
Serial.println("SubString:");
Serial.println(substring);
Serial.println("SubString Length:");
Serial.println(substring.length());
// Create a Char Array to Store the Substring for conversion
char valueArray[substring.length() + 1];
Serial.println("sizeof ValueArray");
Serial.println(sizeof(valueArray));
// Copy the substring into the array
substring.toCharArray(valueArray, sizeof(valueArray));
Serial.println("valueArray:");
Serial.println(valueArray);
// Convert char array to an int value
int value = int(valueArray);
Serial.println("Integer Value:");
Serial.println(value);
// Write the Value to the LEDPin
analogWrite(LEDPin, value);
}
And the serial output looks like this:
Received packet of size 11
From 192.168.1.4, port 58615
Contents:
LEDDimm=100
SubString:
100
SubString Length:
3
sizeof ValueArray
4
valueArray:
100
Integer Value:
2225
I expected to get an int with the value of 100 but the actual int is 2225?! What have I done wrong here?
There is even an (undocumented) toInt() method in the String class:
int myInt = myString.toInt();
You need to use the function int value = atoi(valueArray); where valueArray is a null terminated string.
The toInt () method is very useful in this aspect, but I found that it is able to convert only strings of length five or less, especially a value less than 65535 as its the maximum value int can take. Over this value, it just gives random numbers (overflowing values). Please be aware of this when you use this method as it killed a lot of my useful time to figure this out. Hope it helps.

Resources