Skip to content

Instantly share code, notes, and snippets.

@dgryski
Created November 5, 2015 13:58
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save dgryski/ed398334c75982652800 to your computer and use it in GitHub Desktop.
Save dgryski/ed398334c75982652800 to your computer and use it in GitHub Desktop.

Introduction

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

Strings

Introduction

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

Accessing Substrings

// -----------------------------
// 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*
#-----------------------------

Establishing a Default Value

/*
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.
*/

Exchanging Values Without Using Temporary Variables

// -----------------------------
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
// -----------------------------

Converting Between ASCII Characters and Values

// -----------------------------
// 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);

Reversing a String by Word or Character

// ----------------------------- 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
#-----------------------------

Expanding and Compressing Tabs

# 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($_) }
#-----------------------------

Expanding Variables in User Input

# 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;
#-----------------------------

Controlling Case

// ----------------------------- 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";

capitalize various parts of $beast

capit = strings.Title(beast); // Dromedary capall = strings.ToUpper(beast); // DROMEDARY #-----------------------------

capitalize each word's first character, downcase the rest

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);
#-----------------------------

Interpolating Functions and Expressions Within Strings

// TODO(dgryski): simple string concatenation and text/template

Indenting Here Documents

// Go does not have heredocs

Reformatting Paragraphs

Escaping Characters

Trimming Blanks from the Ends of a String

// -----------------------------
str = strings.TrimSpace(str)
// -----------------------------

Parsing Comma-Separated Data

encoding/csv

Soundex Matching

Program: fixstyle

Program: psgrep

Numbers

Checking Whether a String Is a Valid Number

Comparing Floating-Point Numbers

Rounding Floating-Point Numbers

Converting Between Binary and Decimal

Operating on a Series of Integers

Working with Roman Numerals

Generating Random Numbers

Generating Different Random Numbers

Making Numbers Even More Random

Generating Biased Random Numbers

Doing Trigonometry in Degrees, not Radians

Calculating More Trigonometric Functions

Taking Logarithms

Multiplying Matrices

Using Complex Numbers

Converting Between Octal and Hexadecimal

Putting Commas in Numbers

Printing Correct Plurals

Program: Calculating Prime Factors

Dates and Times

Introduction

Finding Today's Date

Converting DMYHMS to Epoch Seconds

Converting Epoch Seconds to DMYHMS

Adding to or Subtracting from a Date

Difference of Two Dates

Day in a Week/Month/Year or Week Number

Parsing Dates and Times from Strings

Printing a Date

High-Resolution Timers

Short Sleeps

Program: hopdelta

Arrays

Introduction

Specifying a List In Your Program

Printing a List with Commas

Changing Array Size

Doing Something with Every Element in a List

Iterating Over an Array by Reference

Extracting Unique Elements from a List

Finding Elements in One Array but Not Another

Computing Union, Intersection, or Difference of Unique Lists

Appending One Array to Another

Reversing an Array

Processing Multiple Elements of an Array

Finding the First List Element That Passes a Test

Finding All Elements in an Array Matching Certain Criteria

Sorting an Array Numerically

Sorting a List by Computable Field

Implementing a Circular List

Randomizing an Array

Program: words

Program: permute

Hashes

Introduction

Adding an Element to a Hash

Testing for the Presence of a Key in a Hash

Deleting from a Hash

Traversing a Hash

Printing a Hash

Retrieving from a Hash in Insertion Order

Hashes with Multiple Values Per Key

Inverting a Hash

Sorting a Hash

Merging Hashes

Finding Common or Different Keys in Two Hashes

Hashing References

Presizing a Hash

Finding the Most Common Anything

Representing Relationships Between Data

Program: dutree

Pattern Matching

Introduction

Copying and Substituting Simultaneously

Matching Letters

Matching Words

Commenting Regular Expressions

Finding the Nth Occurrence of a Match

Matching Multiple Lines

Reading Records with a Pattern Separator

Extracting a Range of Lines

Matching Shell Globs as Regular Expressions

Speeding Up Interpolated Matches

Testing for a Valid Pattern

Honoring Locale Settings in Regular Expressions

Approximate Matching

Matching from Where the Last Pattern Left Off

Greedy and Non-Greedy Matches

Detecting Duplicate Words

Expressing AND, OR, and NOT in a Single Pattern

Matching Multiple-Byte Characters

Matching a Valid Mail Address

Matching Abbreviations

Program: urlify

Program: tcgrep

Regular Expression Grabbag

File Access

Introduction

Opening a File

Opening Files with Unusual Filenames

Expanding Tildes in Filenames

Making Perl Report Filenames in Errors

Creating Temporary Files

Storing Files Inside Your Program Text

Writing a Filter

Modifying a File in Place with Temporary File

Modifying a File in Place with -i Switch

Modifying a File in Place Without a Temporary File

Locking a File

Flushing Output

Reading from Many Filehandles Without Blocking

Doing Non-Blocking I/O

Determining the Number of Bytes to Read

Storing Filehandles in Variables

Caching Open Output Filehandles

Printing to Many Filehandles Simultaneously

Opening and Closing File Descriptors by Number

Copying Filehandles

Program: netlock

Program: lockarea

File Contents

Introduction

Reading Lines with Continuation Characters

Counting Lines (or Paragraphs or Records) in a File

Processing Every Word in a File

Reading a File Backwards by Line or Paragraph

Trailing a Growing File

Picking a Random Line from a File

Randomizing All Lines

Reading a Particular Line in a File

Processing Variable-Length Text Fields

Removing the Last Line of a File

Processing Binary Files

Using Random-Access I/O

Updating a Random-Access File

Reading a String from a Binary File

Reading Fixed-Length Records

Reading Configuration Files

Testing a File for Trustworthiness

Program: tailwtmp

Program: tctee

Program: laston

Directories

Introduction

Getting and Setting Timestamps

Deleting a File

Copying or Moving a File

Recognizing Two Names for the Same File

Processing All Files in a Directory

Globbing, or Getting a List of Filenames Matching a Pattern

Processing All Files in a Directory Recursively

Removing a Directory and Its Contents

Renaming Files

Splitting a Filename into Its Component Parts

Program: symirror

Program: lst

Subroutines

Introduction

Accessing Subroutine Arguments

Making Variables Private to a Function

Creating Persistent Private Variables

Determining Current Function Name

Passing Arrays and Hashes by Reference

Detecting Return Context

Passing by Named Parameter

Skipping Selected Return Values

Returning More Than One Array or Hash

Returning Failure

Prototyping Functions

Handling Exceptions

Saving Global Values

Redefining a Function

Trapping Undefined Function Calls with AUTOLOAD

Nesting Subroutines

Program: Sorting Your Mail

References and Records

Introduction

Taking References to Arrays

Making Hashes of Arrays

Taking References to Hashes

Taking References to Functions

Taking References to Scalars

Creating Arrays of Scalar References

Using Closures Instead of Objects

Creating References to Methods

Constructing Records

Reading and Writing Hash Records to Text Files

Printing Data Structures

Copying Data Structures

Storing Data Structures to Disk

Transparently Persistent Data Structures

Program: Binary Trees

Packages, Libraries, and Modules

Introduction

Defining a Module's Interface

Trapping Errors in require or use

Delaying use Until Run Time

Making Variables Private to a Module

Determining the Caller's Package

Automating Module Clean-Up

Keeping Your Own Module Directory

Preparing a Module for Distribution

Speeding Module Loading with SelfLoader

Speeding Up Module Loading with Autoloader

Overriding Built-In Functions

Reporting Errors and Warnings Like Built-Ins

Referring to Packages Indirectly

Using h2ph to Translate C #include Files

Using h2xs to Make a Module with C Code

Documenting Your Module with Pod

Building and Installing a CPAN Module

Example: Module Template

Program: Finding Versions and Descriptions of Installed Modules

Classes, Objects, and Ties

Introduction

Constructing an Object

Destroying an Object

Managing Instance Data

Managing Class Data

Using Classes as Structs

Cloning Objects

Calling Methods Indirectly

Determining Subclass Membership

Writing an Inheritable Class

Accessing Overridden Methods

Generating Attribute Methods Using AUTOLOAD

Solving the Data Inheritance Problem

Coping with Circular Data Structures

Overloading Operators

Creating Magic Variables with tie

Database Access

Introduction

Making and Using a DBM File

Emptying a DBM File

Converting Between DBM Files

Merging DBM Files

Locking DBM Files

Sorting Large DBM Files

Treating a Text File as a Database Array

Storing Complex Data in a DBM File

Persistent Data

Executing an SQL Command Using DBI and DBD

Program: ggh - Grep Netscape Global History

User Interfaces

Parsing Program Arguments

Testing Whether a Program Is Running Interactively

Clearing the Screen

Determining Terminal or Window Size

Changing Text Color

Reading from the Keyboard

Ringing the Terminal Bell

Using POSIX termios

Checking for Waiting Input

Reading Passwords

Editing Input

Managing the Screen

Controlling Another Program with Expect

Creating Menus with Tk

Creating Dialog Boxes with Tk

Responding to Tk Resize Events

Removing the DOS Shell Window with Windows Perl/Tk

Program: Small termcap program

Program: tkshufflepod

Process Management and Communication

Gathering Output from a Program

Running Another Program

Replacing the Current Program with a Different One

Reading or Writing to Another Program

Filtering Your Own Output

Preprocessing Input

Reading STDERR from a Program

Controlling Input and Output of Another Program

Controlling the Input, Output, and Error of Another Program

Communicating Between Related Processes

Making a Process Look Like a File with Named Pipes

Sharing Variables in Different Processes

Listing Available Signals

Sending a Signal

Installing a Signal Handler

Temporarily Overriding a Signal Handler

Writing a Signal Handler

Catching Ctrl-C

Avoiding Zombie Processes

Blocking Signals

Timing Out an Operation

Program: sigrand

Sockets

Introduction

Writing a TCP Client

Writing a TCP Server

Communicating over TCP

Setting Up a UDP Client

Setting Up a UDP Server

Using UNIX Domain Sockets

Identifying the Other End of a Socket

Finding Your Own Name and Address

Closing a Socket After Forking

Writing Bidirectional Clients

Forking Servers

Pre-Forking Servers

Non-Forking Servers

Writing a Multi-Homed Server

Making a Daemon Server

Restarting a Server on Demand

Program: backsniff

Program: fwdport

Internet Services

Simple DNS Lookups

Being an FTP Client

Sending Mail

Reading and Posting Usenet News Messages

Reading Mail with POP3

Simulating Telnet from a Program

Pinging a Machine

Using Whois to Retrieve Information from the InterNIC

Program: expn and vrfy

CGI Programming

Introduction

Writing a CGI Script

Redirecting Error Messages

Fixing a 500 Server Error

Writing a Safe CGI Program

Making CGI Scripts Efficient

Executing Commands Without Shell Escapes

Formatting Lists and Tables with HTML Shortcuts

Redirecting to a Different Location

Debugging the Raw HTTP Exchange

Managing Cookies

Creating Sticky Widgets

Writing a Multiscreen CGI Script

Saving a Form to a File or Mail Pipe

Program: chemiserie

Web Automation

Introduction

Fetching a URL from a Perl Script

Automating Form Submission

Extracting URLs

Converting ASCII to HTML

Converting HTML to ASCII

Extracting or Removing HTML Tags

Finding Stale Links

Finding Fresh Links

Creating HTML Templates

Mirroring Web Pages

Creating a Robot

Parsing a Web Server Log File

Processing Server Logs

Program: htmlsub

Program: hrefsub

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment