Ch. 7 String Manipulation
Toul
Posted on April 13, 2023
In this chapter, I'm sharing the string manipulation cheatsheet in part I. to keep on hand for reference when working with strings, which you will be doing a lot of when it comes to automating day-to-day work. Then, you'll find a few useful projects to help flex your string manipulation learnings in part II.
Note: Here's the GitHub for the Project Section after the Cheat Sheet
I. String Manipulation cheatsheet
Print this out, tape it by your desk, or put it in your favorite three-ring binder for school. It contains almost every string manipulation with an expression as an example for when you're working.
String Literals
II. Projects
Regex E-Mail finder from clipboard
In this project, we'll use Regex to determine if a piece of text copied to our clipboard contains an e-mail. The pattern of finding an e-mail in a string of text is handy as you'll probably receive data where it will be useful to the group based on a common characteristic.
If you're interested in building a web application with sign-up / sign-in input fields based on e-mails, this can be useful for determining whether the input is of the correct form.
Note: There is a third-party package dependency in this project, but I trust you remember how to handle that requirement hint go mod init & go get
package main
import (
"fmt"
"regexp"
"strings"
"github.com/atotto/clipboard"
)
func main() {
// create email regexp
regMail, _ := regexp.Compile(`[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}`)
// read os buffer
// find email regexp
text, _ := clipboard.ReadAll()
var mailAddr []string
// found e-mail
if regMail.MatchString(text) {
mailAddr = regMail.FindAllString(text, -1)
}
// Print found e-mails on the terminal
if len(mailAddr) > 0 {
clipboard.WriteAll(strings.Join(mailAddr, "\n"))
fmt.Println("Copied to clipboard:")
fmt.Println(strings.Join(mailAddr, "\n"))
} else {
fmt.Println("No email addresses found.")
}
}
Regex Password Complexity Checker
Password complexity is an additional feature you will want to have for an application. This is because simple passwords are easier for cyber criminals to obtain/guess.
Hence, it is wise to enforce a password complexity of at least 11 characters with some capital letters and numbers thrown in. So, let's build a small program to check whether or not a given password passes the complexity requirement.
package main
import (
"fmt"
"os"
"regexp"
"flag"
)
func main() {
if len(os.Args) < 2 {
fmt.Printf("Usage: %s -h\n", os.Args[0])
} else {
pass := flag.String("p", "", "get password")
flag.Parse()
regStr, _ := regexp.Compile(`([0-9a-zA-Z]){11,}`)
if regStr.MatchString(*pass) {
fmt.Println("Password ok")
} else {
fmt.Println("Bad password")
}
os.Exit(0)
}
}
Running the program and passing in your possible password should result in either a Password OK or Bad Password response from the program:
t@m1 regexppass % go run main.go --p=23498aosethuaosthAT
Pass ok
t@m1 regexppass % go run main.go --p=2Aoeue
Bad password
t@m1 regexppass % go run main.go --p=2AoeueEEEE
Bad password
Quiz Builder
Now, this project is the first in our queue at automating a mundane work task--your teacher friends will love you!
In this project, you'll build a quiz generator around the U.S. and its capitals. However, you will generally have the format of a quiz-building piece of software that can be changed to generate different sorts of quizzes. Maybe, you'll change it to do the capitals of your home country and its states.
package main
import (
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
capitals := map[string]string{
"Alabama": "Montgomery",
"Alaska": "Juneau",
"Arizona": "Phoenix",
"Arkansas": "Little Rock",
"California": "Sacramento",
"Colorado": "Denver",
"Connecticut": "Hartford",
"Delaware": "Dover",
"Florida": "Tallahassee",
"Georgia": "Atlanta",
"Hawaii": "Honolulu",
"Idaho": "Boise",
"Illinois": "Springfield",
"Indiana": "Indianapolis",
"Iowa": "Des Moines",
"Kansas": "Topeka",
"Kentucky": "Frankfort",
"Louisiana": "Baton Rouge",
"Maine": "Augusta",
"Maryland": "Annapolis",
"Massachusetts": "Boston",
"Michigan": "Lansing",
"Minnesota": "Saint Paul",
"Mississippi": "Jackson",
"Missouri": "Jefferson City",
"Montana": "Helena",
"Nebraska": "Lincoln",
"Nevada": "Carson City",
"New Hampshire": "Concord",
"New Jersey": "Trenton",
"New Mexico": "Santa Fe",
"New York": "Albany",
"North Carolina": "Raleigh",
"North Dakota": "Bismarck",
"Ohio": "Columbus",
"Oklahoma": "Oklahoma City",
"Oregon": "Salem",
"Pennsylvania": "Harrisburg",
"Rhode Island": "Providence",
"South Carolina": "Columbia",
"South Dakota": "Pierre",
"Tennessee": "Nashville",
"Texas": "Austin",
"Utah": "Salt Lake City",
"Vermont": "Montpelier",
"Virginia": "Richmond",
"Washington": "Olympia",
"West Virginia": "Charleston",
"Wisconsin": "Madison",
"Wyoming": "Cheyenne",
}
var states, capitalsItems []string
for y, x := range capitals {
capitalsItems = append(capitalsItems, x)
states = append(states, y)
}
for i := 0; i < 35; i++ {
// сreate the quiz text file
str1 := "quiz_" + strconv.Itoa(i+1) + ".txt"
quizFile, err := os.Create(str1)
check(err)
defer quizFile.Close()
// create the answer key to the quiz
str2 := "answer_key_" + strconv.Itoa(i+1) + ".txt"
answerKeyFile, err := os.Create(str2)
check(err)
defer answerKeyFile.Close()
// Create portion for students to fill out
quizFile.WriteString("Student Number:\n\nName:\n\nDate:\n\n")
str3 := "Quiz " + strconv.Itoa(i+1)
quizFile.WriteString(strings.Repeat(" ", 20) + str3)
quizFile.WriteString("\n\n")
rand.Seed(time.Now().UnixNano())
// mix of the States
shuffle(states)
// Iterate through and build the question out
for j := 0; j < 50; j++ {
correctAnswer := capitals[states[j]]
wrongAnswers := make([]string, len(capitalsItems))
copy(wrongAnswers, capitalsItems)
// shuffle wrong answers
answNoCorrect := make([]string, len(wrongAnswers)-1)
for l := 0; l < len(wrongAnswers); l++ {
if wrongAnswers[l] == correctAnswer {
copy(answNoCorrect, removeAtIndex(wrongAnswers, l))
}
}
// create answer options A-D
var answerOptions []string
for l := 0; l < 3; l++ {
answerOptions = append(answerOptions, answNoCorrect[l])
}
answerOptions = append(answerOptions, correctAnswer)
shuffle(answerOptions)
// create question
str3 := strconv.Itoa(j+1) + " What is the Capital of " + states[j] + "?" + "\n"
quizFile.WriteString(str3)
strAbcd := "ABCD"
for l := 0; l < 4; l++ {
strAnsw := string(strAbcd[l]) + ". " + answerOptions[l] + "\n"
quizFile.WriteString(strAnsw)
}
// make quiz and save it
quizFile.WriteString("\n")
// make answer key and save it
strAnswerOk := ""
for l := 0; l < len(answerOptions); l++ {
if answerOptions[l] == correctAnswer {
strAnswerOk += string(strAbcd[l])
}
}
strCorAnsw := strconv.Itoa(j+1) + ". " + strAnswerOk + "\n"
answerKeyFile.WriteString(strCorAnsw)
}
}
}
// helper functions for making quiz building easier
func check(e error) {
if e != nil {
panic(e)
}
}
func shuffle(a []string) {
for i := range a {
j := rand.Intn(i + 1)
a[i], a[j] = a[j], a[i]
}
}
func removeAtIndex(source []string, index int) []string {
lastIndex := len(source) - 1
source[index], source[lastIndex] = source[lastIndex], source[index]
return source[:lastIndex]
}
There you have it, the foundation of all the string knowledge you'll use to work with string data in files, clipboards, or anywhere else.
Posted on April 13, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.