-2

I am a beginner in Golang...

I found that rune(char) == "-" has been used to check if a character in a word matches with hyphen instead of checking it as char == "-".

Here is the code:

package main

import (
    "fmt"
    "unicode"
)

func CodelandUsernameValidation(str string) bool {

  // code goes here
  if len(str) >= 4 && len(str) <= 25   {
   if unicode.IsLetter(rune(str[0])) {
       for _,char := range str {
        if !unicode.IsLetter(rune(char)) && !unicode.IsDigit(rune(char)) &&  !(rune(char) == '_') {
          return false
          
        }
       }
       return true
   }
  }
  return false;

}

func main() {

  // do not modify below here, readline is our function
  // that properly reads in the input for you
  var user string
  fmt.Println("Enter Username")
  fmt.Scan(&user)
  fmt.Println(CodelandUsernameValidation(user))

}

Could you please clarify why rune is required here?

Rad4
  • 1,936
  • 8
  • 30
  • 50
  • 3
    `rune(char)` is not a function call, it's a type [conversion](https://go.dev/ref/spec#Conversions). `rune(char) == "-"` is a compile time error. Please provide a [mcve]. – icza Jan 31 '22 at 20:55
  • I have updated the code.. – Rad4 Feb 01 '22 at 00:14
  • Does this answer your question? [What is a rune?](https://stackoverflow.com/questions/19310700/what-is-a-rune) – Cristik Feb 03 '22 at 07:22

3 Answers3

1

The code in the question must convert the byte str[0] to a rune for the call to unicode.IsLetter. Otherwise, the rune conversions are not needed.

The required byte to rune conversion hints a problem: The application is treating a byte as a rune, but bytes are not runes.

Fix by using for range to iterate through the runes in the string. This eliminates conversions from the code:

func CodelandUsernameValidation(str string) bool {
    if len(str) < 4 || len(str) > 25 {
        return false
    }
    for i, r := range str {
        if i == 0 && !unicode.IsLetter(r) {
            // str must start with a letter
            return false
        } else if !unicode.IsLetter(r) && !unicode.IsDigit(r) && !(r == '_') {
            // str is restricted to letters, digit and _.
            return false
        }
    }
    return true
}
1

The first thing we need to know is that rune is nothing but an alias of int32. Single quotes represent a rune and double quotes represent a string. so instead of this rune(char) == "-" it should be rune(char) == '-'.

comment from builtin package

// rune is an alias for int32 and is equivalent to int32 in all ways. It is // used, by convention, to distinguish character values from integer values.

Second, here we need to know that A loop over the string and accesses it by index returns individual bytes, not characters. like here unicode.IsLetter(rune(str[0])). str[0] returns a byte which is the alias of uint8 not characters. it will fail for some cases because some characters encoded have a length of more than 1 byte because UTF-8. for example take this character ⌘ is represented by the bytes [e2 8c 98] and that those bytes are the UTF-8 encoding, in your example code if you try to access str[0] it will return e2 which may an invalid UTF-8 codepoint or it will represent another character which is a single UTF-8 encoded byte. so here you do like this

strbytes := []byte(str)

firstChar, size := utf8.DecodeRune(strbytes )

A for range loop, by contrast, decodes one UTF-8-encoded rune on each iteration. Each time around the loop, the index of the loop is the starting position of the current rune, measured in bytes, and the code point is its value. so in the example code for _,char := range str { the type of char is rune and again you are trying to convert rune to rune which is duplicated the work.

if want to learn more about strings how they work in Golang here is a great post by Rob Pike

Manjeet Thakur
  • 2,288
  • 1
  • 16
  • 35
0

You need to translate from str to []rune

r := []rune(str)

This must be the first line in the function CodelandUsernameValidation.

Tahuri
  • 11
  • 2