A Go version of The Perl Cookbook
The Perl part is copyrighted by O'Reilly & Associates yet freely available.
This copy is based on http://pleac.sourceforge.net/pleac_perl.data
str = '\n' // two characters, \ and an n
str = "Jon 'Maddog' Orwant" // literal single quotes
// -----------------------------
str = "\n"; // a "newline" character
str = "Jon \"Maddog\" Orwant" // literal double quotes
// -----------------------------
// Use ` to for raw strings which avoid any interpretation of the input
str = `Jon 'Maddog' Orwant` // literal single quotes
str = `Jon "Maddog" Orwant` // literal double quotes
// -----------------------------
// Go does not have heredocs
// -----------------------------
// Note that `start` and `end` refer to byte indices, not runes.
value = str[start:]
value = str[:end]
value = str[start:end]
// -----------------------------
// Strings are read-only. To replace the characters from `start` to `end', you must create a new string.
str = str[:start] + newstr + str[end:]
// -----------------------------
// get a 5-byte string, skip 3, then grab 2 8-byte strings, then the rest
leading, s1, s2, trailing := data[:5], data[8:16], data[16:24], data[24:]
// -----------------------------
// split at five byte boundaries
var fivers []string
for len(str) > 5 {
fivers = append(fivers, str[:5])
str = str[5:]
}
fivers = append(fivers, str)
// -----------------------------
// chop string into individual characters
chars := []byte(str)
runes := []rune(str)
// -----------------------------
// indexing
str = "This is what you have";
// 012345678901234567890 Indexing forwards (left to right)
// Go does not support negative indexing.
first := str[:1] // "T"
start := str[5:7] // "is"
rest := str[13:] // "you have"
last := str[len(s)-1:] // "e"
end := str[len(s)-4:] // "have"
piece := str[len(s)-8:len(s)-5] // "you"
// -----------------------------
str := "This is what you have"
fmt.Println(str)
//This is what you have
str = str[:5] + "wasn't" + str[7:] // change "is" to "wasn't"
//This wasn't what you have
str = str[len(s)-12] + "ondrous" // replace last 12 characters
//This wasn't wondrous
s = s[1:] // delete first character
//his wasn't wondrous
str = str[:len(str)-10] // delete last 10 characters
//his wasn'
//-----------------------------
# TODO(dgryski): translate or drop?
# you can test substrings with =~
if (substr($string, -10) =~ /pattern/) {
print "Pattern matches in last 10 characters\n";
}
// substitute "at" for "is", restricted to first five characters
r = []rune(str)
str = strings.Replace(string(r[:5]), "is", "at", -1) + string(r[5:])
#-----------------------------
# exchange the first and last letters in a string
a = "make a hat";
r = []rune(a)
r[0], r[len(r)-1] = r[len(r)-1], r[0]
a = str(r)
fmt.Println(a)
// take a ham
#-----------------------------
# TODO(dgryski): translate or drop?
# extract column with unpack
$a = "To be or not to be";
$b = unpack("x6 A6", $a); # skip 6, grab 6
print $b;
# or not
($b, $c) = unpack("x6 A2 X5 A2", $a); # forward 6, grab 2; backward 5, grab 2
print "$b\n$c\n";
# or
#
# be
#-----------------------------
sub cut2fmt {
my(@positions) = @_;
my $template = '';
my $lastpos = 1;
foreach $place (@positions) {
$template .= "A" . ($place - $lastpos) . " ";
$lastpos = $place;
}
$template .= "A*";
return $template;
}
$fmt = cut2fmt(8, 14, 20, 26, 30);
print "$fmt\n";
# A7 A6 A6 A6 A4 A*
#-----------------------------
/*
The original examples rely heavily on Perl's definition of truth and definedness, as
well as showing off Perl's operators and expression syntax.
In Go, almost all the examples become a simple if statment.
*/
// -----------------------------
var1, var2 = var2, var1
// -----------------------------
temp = a
a = b
b = temp
// -----------------------------
a = "alpha"
b = "omega"
a, b = b, a // the first shall be the last, and versa vice
// -----------------------------
alpha, beta, production := "January", "March", "August
// move beta to alpha,
// move production to beta,
// move alpha to production
alpha, beta, production) = beta, production, alpha
// -----------------------------
// -----------------------------
// characters are integer types in Go, either byte (uint8) or rune.
// Convert them with the normal type conversions, if needed.
num = int(char)
char = rune(num)
// -----------------------------
num = 101
char = 'e'
fmt.Printf("Number %d is character %c\n", num, char);
//Number 101 is character e
#-----------------------------
// To convert between a string and an array of bytes or runes, use the standard Go type conversions.
ascii = []byte(string)
runes = []rune(string)
str1, str2 = string(ascii), string(runes)
#-----------------------------
// characters and integers are (for the most part) interchangeable
ascii_value = 'e'
character = 101
#-----------------------------
fmt.Printf("Number %d is character %c\n", 101, 101);
#-----------------------------
ascii = []byte("sample")
fmt.Println(ascii)
// [115 97 109 112 108 101]
word = string(ascii)
fmt.Println(word)
// sample
// -----------------------------
hal = "HAL";
ascii = []byte(hal)
for i := range ascii {
ascii[i]++ // add one to each ASCII value
}
ibm = string(ascii)
fmt.Println(ibm) // prints IBM
// -----------------------------
### Processing a String One Character at a Time
// -----------------------------
// strings can be converted to utf8 bytes or unicode runes
bytes = []byte(string)
runes = []rune(string)
// -----------------------------
// this iterates over the unicode runes in str
for r := range str {
// do something with r
}
// -----------------------------
// To sort runes in a string, we must define a rune slice
type rslice []rune
func (r rslice) Len() int { return len(r) }
func (r rslice) Less(i, j int) bool { return r[i] < r[j] }
func (r rslice) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
// Then we can use it:
seen := make(map[rune]int)
str := `an apple a day`
for _, r := range str {
seen[r]++
}
var runes rslice
for k, _ := range seen {
runes = append(runes, k)
}
sort.Sort(runes)
fmt.Println("unique chars are: ", string(runes))
// unique chars are: adelnpy
#-----------------------------
sum = 0;
for _, c := range str {
sum += c
}
fmt.Println("sum is", sum)
# prints "1248" if string was "an apple a day"
#-----------------------------
```perl
# TODO(dgryski): translate or drop
$sum = unpack("%32C*", $string);
// ----------------------------- func reverseString(s string) string { r := []rune(s) for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { r[i], r[j] = r[j], r[i] } return string(r) } // ----------------------------- func reverseWords(s []string) string { for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { s[i], s[j] = s[j], s[i] } } reversed := strings.Join(reverseWords(strings.Split(str, " ")), " ") // ----------------------------- gnirts = reverseString(str); // reverse letters in str
sdrow = reverseWords(@words); // reverse elements in @words
confused = strings.Join(reverseWords(@words), ""); // reverse letters in join("", @words)
// -----------------------------
// reverse word order
str := Yoda said, "can you see this?"
allwords := strings.Split(str, " ")
revwords = strings.Join(reverseWords(allwords), " ")
fmt.Println(revwords)
// this?" see you "can said, Yoda
// -----------------------------
revwords := strings.Join(reverseWords(strings.Split(str, " ")), " ")
// -----------------------------
word := "reviver";
isPalindrome := word == reverseString(word)
// -----------------------------
//
```perl
# TODO(dgryski): translate to Go
#% perl -nle 'print if $_ eq reverse && length > 5' /usr/dict/words
#deedeed
#
#degged
#
#deified
#
#denned
#
#hallah
#
#kakkak
#
#murdrum
#
#redder
#
#repaper
#
#retter
#
#reviver
#
#rotator
#
#sooloos
#
#tebbet
#
#terret
#
#tut-tut
#-----------------------------
# TODO(dgryski): translate to Go
while ($string =~ s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e) {
# spin in empty loop until substitution finally fails
}
#-----------------------------
use Text::Tabs;
@expanded_lines = expand(@lines_with_tabs);
@tabulated_lines = unexpand(@lines_without_tabs);
#-----------------------------
while (<>) {
while s/\t+/' ' x (length($&) * 8 - length($`) % 8)/e;
print;
}
#-----------------------------
use Text::Tabs;
$tabstop = 4;
while (<>) { print expand($_) }
#-----------------------------
use Text::Tabs;
while (<>) { print unexpand($_) }
#-----------------------------
# TODO(dgryski): translate to Go
#-----------------------------
#You owe $debt to me.
#-----------------------------
$text =~ s/\$(\w+)/${$1}/g;
#-----------------------------
$text =~ s/(\$\w+)/$1/gee;
#-----------------------------
use vars qw($rows $cols);
no strict 'refs'; # for ${$1}/g below
my $text;
($rows, $cols) = (24, 80);
$text = q(I am $rows high and $cols long); # like single quotes!
$text =~ s/\$(\w+)/${$1}/g;
print $text;
I am 24 high and 80 long
#-----------------------------
$text = "I am 17 years old";
$text =~ s/(\d+)/2 * $1/eg;
#-----------------------------
2 * 17
#-----------------------------
$text = 'I am $AGE years old'; # note single quotes
$text =~ s/(\$\w+)/$1/eg; # WRONG
#-----------------------------
'$AGE'
#-----------------------------
$text =~ s/(\$\w+)/$1/eeg; # finds my() variables
#-----------------------------
# expand variables in $text, but put an error message in
# if the variable isn't defined
$text =~ s{
\$ # find a literal dollar sign
(\w+) # find a "word" and store it in $1
}{
no strict 'refs'; # for $$1 below
if (defined ${$1}) {
${$1}; # expand global variables only
} else {
"[NO VARIABLE: \$$1]"; # error msg
}
}egx;
#-----------------------------
// ----------------------------- big = strings.ToUpper(little); // "bo peep" -> "BO PEEP" little = strings.ToLower(big); // "JOHN" -> "john" #----------------------------- runes = []rune(str) big = string(unicode.ToUpper(runes[0]) + runes[1:]) // "bo" -> "Bo" big = string(unicode.ToLower(runes[0]) + runes[1:]) // "BoPeep" -> "boPeep" #----------------------------- beast = "dromedary";
capit = strings.Title(beast); // Dromedary capall = strings.ToUpper(beast); // DROMEDARY #-----------------------------
text = "thIS is a loNG liNE"; text = strings.Title(strings.ToLower(text)) fmt.Println(text) // This Is A Long Line #----------------------------- if strings.ToUpper(a) == strings.ToUpper(b) { fmt.Println("a and b are the same") }
```perl
# TODO(dgryski): These fail on 8-bit and unicode characters. Built something with unicode.SimpleFold() ?
#-----------------------------
# ^^INCLUDE^^ include/perl/ch01/randcap
#% randcap < genesis | head -9
#boOk 01 genesis
#
#
#001:001 in the BEginning goD created the heaven and tHe earTh.
#
#
#
#001:002 and the earth wAS without ForM, aND void; AnD darkneSS was
#
# upon The Face of the dEEp. and the spIrit of GOd movEd upOn
#
# tHe face of the Waters.
#
#
#001:003 and god Said, let there be ligHt: and therE wAs LigHt.
#-----------------------------
sub randcase {
rand(100) < 20 ? ("\040" ^ $_[0]) : $_[0];
}
#-----------------------------
$string &= "\177" x length($string);
#-----------------------------
// TODO(dgryski): simple string concatenation and text/template
// Go does not have heredocs
// -----------------------------
str = strings.TrimSpace(str)
// -----------------------------
encoding/csv