CS 312 - Week 3.1 Class
CS 312 Audio Programming Winter 2020
Table of Contents
3.1 Class
Setup
- Mount your course folder using the Go menu in Mac Finder:
smb://courses.ads.carleton.edu/COURSES/cs312-00-w20 - Open Mac Terminal
- Execute:
setup312 <your_carleton_email_name>
cd $HOME312/cs312 mkdir hw31 cd hw31 mkdir c311_regex_example1 cd c311_regex_example1 touch c311_regex.txt cd $HOME312/cs312/hw31 mkdir c312_regex_example2 cd c312_regex_example2 touch c312_regex2.txt cd $HOME312/cs312/hw31 mkdir c313_regex_example3 cd c313_regex_example3 mkdir build touch c313_helloMidi_regex.cpp touch c313_helloMidi.txt touch CMakeLists.txt
Download
hw312_CMidiPacketFriends.zip
Execute in Mac Terminal
cd $HOME312/cs312/hw31 unzip ~/Downloads/hw312_CMidiPacketFriends.zip -d $HOME312/cs312/hw31/ cd $HOME312/cs312/hw31 rm -fR __MACOSX cp hw312_CMidiPacketFriends/hw312_CMidiPacket.h c313_regex_example3/ cp hw312_CMidiPacketFriends/hw312_CMidiPacket.cpp c313_regex_example3/
Regular Expressions (regex)
In theoretical computer science and formal language theory, a regular expression (abbreviated regex or regexp and sometimes called a rational expression) is a sequence ofcharacters that define a search pattern, mainly for use in pattern matching with strings, or string matching, i.e. "find and replace"-like operations. The concept arose in the 1950s, when the American mathematician Stephen Kleene formalized the description of a regular language, and came into common use with the Unix text processing utilities ed, an editor, and grep (global regular expression print), a filter.
Regular expressions are so useful in computing that the various systems to specify regular expressions have evolved to provide both a basic and extended standard for the grammar and syntax; modern regular expressions heavily augment the standard. Regular expression processors are found in several search engines, search and replace dialogs of several word processorsand text editors, and in the command lines of text processing utilities, such as sed and AWK.
Many programming languages provide regular expression capabilities, some built-in, for example Perl, JavaScript, Ruby, AWK, and Tcl, and others via a standard library, for example .NET languages, Java, Python, POSIX C and C++ (since C++11). Most other languages offer regular expressions via a library."
https://en.wikipedia.org/wiki/Regular_expression
Regex expressions and abbreviations
. | Find any single character |
.* | Find zero or more of any character. In effect find to the end of the line |
5. | Find the number 5 followed by any single character |
[0-9] brackets define a range | In this case search for a single digit zero to nine |
[0-9]+ | + means one or more. Find one or more digits |
[0-9]* | * means zero or more. Find zero or more digits |
[0-9]+? | ? means don't be greedy. Stop after the first match |
^ | ^ means the beginning of a line |
$ | $ means the end of a line |
^[0-9]+ | Find one or more digits at the beginning of a line |
[0-9]+$ | Find one or more digits at the end of the line |
[^0-9]+ | ^ inside a range negates the range. Find anything thats not a number |
[0-9]{4} | The {4} means exactly 4 digits. Find a four digit number |
[0-9]{2,4} | Find a number of 2 to 4 digits |
[0-9A-Fa-fx]+ | Find any decimal or hexadecimal number (0-9 A-F a-f x) |
[80|90] | Find 80 or 90 |
[8|9]2 | Find 82 or 92 |
\d | Find a decimal digit (0-9) |
\s | Find any single whitespace character (tabs or spaces) |
\w | Find any alpha-numeric character A-Z a-z 0-9 and _ |
\D | Not a decimal digit |
\S | Not a whitespace character |
\W | Not a alpha-numeric character |
\w+ | Find all alphanumeric characters |
\w+? | Find all alphanumeric characters stop at first found |
[^\w]+ | Find all non alpha-numeric characters like whitespace between words |
\W+ | Same as above, find all non alpha-numeric characters |
c311_regex_example1
Open the c311_regex_example1 folder.
You're given a list of names <firstname> <lastname>.
c311_regex.txt
Copy/paste
Emeli Barlow Vernon Chapman Kyle Thorne Kelsey Bauer Primrose Bone Jago Hoover Klay Fitzpatrick Alysia Villegas Viktor Worthington
You need to format them into CSV format (Comma Separated Values) for importing into a database.
The database requires this order <lastname>, <firstname>.
We'll use regular expressions to get the job done.
Open the the Find/Replace panel and turn on Use Regular Expression.
- Shortcuts
Command-F opens Find section only
Command-Option-F opens Find and Replace sections.
Use this regular expression for Find.
(\w+)\s+(\w+)
All matches will be highlighted.
Notes on the Find regex
Parentheses enclose replacement groups named $1, $2, $3…
( | begin replacement group $1 |
\w+ | one or more alphanumeric character [a-zA-Z0-9] |
) | end replacement group $1 |
\s+ | one or more spaces or tabs |
( | begin replacement group $2 |
\w+ | one or more alphanumeric character [a-zA-Z0-9] |
) | end replacement group $2 |
Use this regular expression for Replace.
$2, $1
Click Replace All.
Notes on the Replace regex
$1 | replacement group $1 from Find regex |
, | insert comma space |
$2 | replacement group $2 from Find regex |
Close the Find/Replace panel.
Job done.
Note the same regular expression would work on a list of 100,000 names just as easily and almost as quickly.
c312_regex_example2
Setup
Open the c312_regex_example2 folder in vsCode.
We'll parse MIDIDisplay_DLS message strings using regular expressions.
c312_regex2.txt
Copy/paste.
Lines 1-2 use tabs.
Line 3 uses spaces.
100 c0 11 1001 91 61 101 1002 B2 7 102
Turn on Render Whitespace from the View menu.
Make sure you see the tab arrow separating numbers in lines 1 and 2
Make sure you see the space dot separating numbers in line 3.
Open the the Find/Replace panel and turn on Use Regular Expression.
- Shortcuts
- Command-F opens Find section only
Command-Option-F opens Find and Replace sections.
You can widen the Find/Replace panel by dragging the left edge.
Turn on Use Regular Expression
Shortcut: Command-Option-R
Enter these terms
^(\w+)\s+(\w+)\s+(\w+)\s*(\w*)$ $1\n$2\n$3\n$4
Click the Replace All icon
Close the Find/Replace panel.
Regex analysis for Find
^(\w+)\s+(\w+)\s+(\w+)\s*(\w*)$
^ | beginning of line | |
(\w+) | one or more alphanumeric character [a-zA-Z0-9] | Replacement $1 |
\s+ | one or more spaces or tabs | |
(\w+) | one or more alphanumeric character [a-zA-Z0-9] | Replacement $2 |
\s+ | one or more spaces or tabs | |
(\w+) | one or more alphanumeric character [a-zA-Z0-9] | Replacement $3 |
\s* | zero or more spaces or tabs | |
(\w*) | zero or more alphanumeric character [a-zA-Z0-9] | Replacement $4 |
$ | end of line |
Regex analysis for Replace
$1\n$2\n$3\n$4
$n | Replacement group n |
\n | New line |
Alternative regex
Search for everything that is not whitespace.
Choose Undo from the Edit menu to revert back to the original text.
Shortcut: Command-Z
Enter these terms.
Find changes.
Replace stays the same.
^(\S+)\s+(\S+)\s+(\S+)\s*(\S*) $1\n$2\n$3\n$4
Click the Replace All icon
Close the Find/Replace panel.
Regex analysis for Find
^(\S+)\s+(\S+)\s+(\S+)\s*(\S*)
^ | beginning of line | |
(\S+) | one or more characters that are not whitespace | Replacement $1 |
\s+ | one or more spaces or tabs | |
(\S+) | one or more characters that are not whitespace | Replacement $2 |
\s+ | one or more spaces or tabs | |
(\S+) | one or more characters that are not whitespace | Replacement $3 |
\s* | zero or more spaces or tabs | |
(\S*) | zero or more characters that are not whitespace | Replacement $4 |
c313_helloMidi_regex
IMPORTANT:
If you have not submitted hw212_CMidiPacket you must turn in what you have completed before you leave class today in order to be graded.
I have reworded the About CS312 web page to stipulate that homework from now on is due at the beginning of class one week later (not the end as was stated previously). That applies to hw222_CMidiPacket due at the beginning of class Wednesday.
The hw312_CMidiPacket.h and hw312_CMidiPacket.cpp are my solutions to hw212_CMidiPacket with some new functions added. You're free to compare my solutions with yours and adopt any changes into current hw222_CMidiPacket.
If you've already submitted hw222_ you may resubmit if you want to. Just add "revised" to the folder name.
I will be giving you my solutions to hw222_CMidiPacket as the starting point for class 3.2.
Setup
Open c312_helloMidi_regex folder in vsCode.
The c313_helloMidi.txt file is the hw131_helloMidi.txt file with all comments removed.
We'll read the file line by line and use the regex matches to initialize and print CMidiPackets.
c313_helloMidi.txt
0 c0 0 0 90 60 110 900 80 60 0 1000 90 55 80 1400 80 55 0 1500 90 55 60 1900 90 55 0 2000 90 56 100 2900 80 56 0 3000 90 55 80 4200 80 55 0 4999 c0 56 5000 90 59 110 5900 80 59 0 6000 90 60 127 8000 80 60 0
c313_helloMidi_regex.cpp
This code is slightly modified from TCPP2 Section 9.4.1, page 116.
Copy/paste
#include <iostream> #include <string> #include <fstream> #include <regex> #ifndef HW312_CMIDIPACKET_H_ #include "hw312_CMidiPacket.h" #endif using namespace CMP31; //From TCPP2 9.4.1 page 116 void line_to_midipacket(std::string line) { // use a Raw string std::regex pat(R"(^(\S+)\s+(\S+)\s+(\S+)\s*(\S*))"); std::smatch matches; if (std::regex_search(line, matches, pat)) { CMidiPacket mp(matches[0]); mp.print(); // std::cout << "# " << matches[1] << '\t' << matches[2] << '\t' << matches[3] << '\t' << matches[4] << std::endl; } } int main() { std::string fname = "../c313_helloMidi.txt"; std::ifstream ifs; ifs.open(fname); if (!ifs.is_open()) { std::cout << fname << " could not be opened" << std::endl; exit(0); } std::string line; while (getline(ifs, line)) line_to_midipacket(line); }
Fix the squiggles
If you open c313_helloMidi_regex.cpp you'll see that vsCode could not find the hw222_CMidiPacket.h file that should be in your common folder.
Fix it.
- Click the squiggle
- Click the light bulb
- Edit the #include path as necessary
CMakeLists.txt
This is our standard CMakeLists.txt template from hw23.
cmake_minimum_required( VERSION 2.8 ) set( APPNAME "helloMidi" ) project( ${APPNAME} ) #edit next line #set( HOME "/Volumes/cs312-00-w20/StuWork/<your_email_name>" ) set( HOME "/Users/je" ) # set( COMMON "${HOME}/cs312/common" ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall " ) set( SOURCE_FILES hw312_CMidiPacket.cpp c313_helloMidi_regex.cpp ) # include_directories( ${COMMON} ) add_executable( ${APPNAME} ${SOURCE_FILES} )
Build and run using cmake
Output
0 c0 0 # 0 c0 0 0 90 60 110 # 0 90 60 110 900 80 60 0 # 900 80 60 0 1000 90 55 80 # 1000 90 55 80 1400 80 55 0 # 1400 80 55 0 1500 90 55 60 # 1500 90 55 60 1900 90 55 0 # 1900 90 55 0 2000 90 56 100 # 2000 90 56 100 2900 80 56 0 # 2900 80 56 0 3000 90 55 80 # 3000 90 55 80 4200 80 55 0 # 4200 80 55 0 4999 c0 56 # 4999 c0 56 5000 90 59 110 # 5000 90 59 110 5900 80 59 0 # 5900 80 59 0 6000 90 60 127 # 6000 90 60 127 8000 80 60 0 # 8000 80 60 0
Note:
Lines beginning with a number were CMidiPackets initialized by string matches[0] and output using mp.print().
Lines beginning with a # are regex replacement group strings output using std::cout
Play it in MIDIDisplay_DLS
Reading
TCPP2 and www materials
- Regular Expressions
- regex
TCCP2 §9.4 all
https://regexr.com/ - Operator overloading
- http://www.learncpp.com/cpp-tutorial/93-overloading-the-io-operators/
http://www.learncpp.com/cpp-tutorial/94-overloading-the-comparison-operators/ - std::sort()
- https://www.geeksforgeeks.org/internal-details-of-stdsort-in-c/
- MIDI review
- http://midi.teragonaudio.com
http://midi.teragonaudio.com/tech/midispec.htm
https://www.nyu.edu/classes/bello/FMT_files/9_MIDI_code.pdf
https://learn.sparkfun.com/tutorials/midi-tutorial/all
https://www.sweetwater.com/insync/midi-essential-guide
https://www.midi.org/specifications-old/item/the-midi-1-0-specification
https://www.midi.org/specifications-old/item/table-1-summary-of-midi-message - friend functions
- https://www.learncpp.com/cpp-tutorial/813-friend-functions-and-classes/
https://en.cppreference.com/w/cpp/language/friend
What are friends for?
- Question
- What is a friend function?
- Answer
- A friend function is a function declared inside a class declaration and specified with the keyword friend. It is a declaration of a function but not an actual class member. Functions declared as friend inside a class declaration (.h file) are given permission to access all private and public functions and data members of that class. In the class implementation (.cpp file) the friend keyword is dropped and the scope operator :: is not used.
- Question
- How can I make CMidiPacket read and write to streams using << and >>?
- Answer
- Overload operator>> for reading
Overload operator<< for writing. - Question
- How can I tell if CMidiPacket A == CMidiPacket B?
- Answer
- Overload operator==. Every data member of A must equal the same data member of B.
- Question
- How can I use std::sort on CMidiPackets?
- Answer
- Overload operator<. It's up to you to determine what less than means.
CMidiPacket's Four Friends
Operator overloads for <<, >>, ==, and <
These four functions will be overloaded to do the correct thing on CMidiPacket objects. Deciding what the "correct thing" is is straightforward in three cases but more complicated for operator less.
- operator<< (put to)
- operator>> (get from)
- operator== (equals)
- operator< (less)
Once those these four operator overload functions have been implemented correctly you can do this.
using namespace CMP31; CMidiPacket A; CMidiPacket B; // print to std::cout std::cout << A; // write to a string stream std::sstream oss; oss << A; // write to a file stream std::fstream outfile; outfile << A; // read from standard input std::cin >> B; // read from a string stream std::sstream iss; iss >> A; // read from a file stream // will probably use getline() // equality if ( A == B ) do_something(); // less than std::sort(A.begin(), A.end()); // or if ( A < B ) do_something_else();
The CMidiPacket operators will work like this.
- std::cout << A
- Will print 100 90 60 100 with tabs between numbers.
The status byte will be hex without 0x prefix
std::cout can be replaced with other output streams like <sstream> for writing to strings and <fstream> for writing to files. - std::cin >> A
- std::cin can be replaced with other intput streams like <sstream> for reading from strings and <fstream> for reading from files.
- A==B
- A==B if and only if all data members are equal.
A.timestamp_ == B.timestamp_, A.status_ == B.status and so on for each data member. - A < B
- Because CMidiPacket (actually any class) implements operator< the std::sort() function will sort CMidiPackets according to those rules.
Homework 3.1
hw311_regex
You've been hired to convert list of 200,000 names and phone numbers into the CSV (Comma Separated Values) format used by the company database. The format of the file you've been given has three fields: firstname, lastname, phone separated by some unknown whitespace characters. The company database has five fields separated by commas: lastname, firstname, areaCode, exchange, number. The company sales force and marketing department use the area code to group customers by states, the exchange by cities and parts of cities, and the number to get in touch with customers.
You want to transform
Debby | Feldman | (678)404-1948 |
into
Feldman | Debby | 678 | 404 | 1948 |
Setup
cd $HOME312/cs312/ mkdir hw31 cd hw31 mkdir hw311_regex cd hw311_regex touch oldDatabase.txt touch hw311_answer.txt code .
oldDatabase.txt
Copy/paste
Justin Creighton (408)274-1391 Sari Dwyer (541)713-2241 Luis Metzler (660)299-4151 Caridad Worthy (225)314-1509 Mana Mckay (361)903-5171 Ryan Pettis (575)443-3333 Chassidy Ott (585)472-1483 Rana Elkins (818)623-8830 Harley Sorenson (443)782-6537 Rosalina Hobbs (402)286-3439 Arlie Pinto (430)994-1641 Henry Samson (407)699-7668 Verena Lockett (732)739-5150 Debby Feldman (678)404-1948 Keenan Vann (641)921-8478 Angelo Bounds (386)397-3184 Taunya Crutchfield (671)635-1188 Russell Zeller (386)283-7545 Rasheeda Winfield (361)216-5271 Elenore Spaulding (617)821-7668 Rima Mcintyre (763)473-5312 Gabrielle Smyth (201)710-6795 Audria Mcfarland (479)820-9842 Dusti Abraham (469)352-1352 Latrina Wendt (513)560-9145
Assignment 3.1.1
Create the vsCode regular expressions for find/replace that produce this transformation.
The company database fields are lastname, firstname, areaCode, exchange, number.
Paste your find and replace regular expressions that produce the following output into hw311_regex.txt.
hw311_answer.txt
Copy/paste
// boilerplate here My find regex is here: My replace regex is here: My converted output is here:
Output
Creighton,Justin,408,274,1391 Dwyer,Sari,541,713,2241 ...
hw312_CMidiPacketFriends
If you have not submitted hw212_CMidiPacket you must turn in what you have completed before you leave class today in order to be graded.
I have reworded the About CS312 web page to stipulate that homework from now on is due at the beginning of class one week later (not the end as was stated previously). That applies to hw222_CMidiPacket due at the beginning of class Wednesday.
The hw312_CMidiPacket.h and hw312_CMidiPacket.cpp are my solutions to hw212_CMidiPacket with some new functions added. You're free to compare my solutions with yours and adopt any changes into current hw222_CMidiPacket.
If you've already submitted hw222_ you may resubmit if you want to. Just add "revised" to the folder name.
I will be giving you my solutions to hw222_CMidiPacket as the starting point for class 3.2.
Open folder hw312_CMidiPacketFriends in vsCode
You should have these files:
$HOME312/cs312/hw31 └── hw312_CMidiPacketFriends ├── CMakeLists.txt ├── build ├── hw312_CMidiPacket.cpp ├── hw312_CMidiPacket.h ├── hw312_main.cpp ├── hw312_test_CMidiPacket.cpp └── hw312_test_CMidiPacket.h
Build and run
cd $HOME312/cs312/hw31/hw312_CMidiPacketFriends/build cmake .. && make && ./cmp31.
The script should execute with no errors and compile and run cmp31.
hw312_CMidiPacket modifications
I've declared four friend functions near the end of the hw312_CMidiPacket.h file.
// NEW FOR hw312_CMidiPacket /****************************** FRIENDS ******************************/ // operator<< for output friend std::ostream &operator<<(std::ostream &os, const CMidiPacket &mp); // operator<< for input friend std::istream &operator>>(std::istream &is, CMidiPacket &mp); // operator== for testing equality friend bool operator==(const CMidiPacket &a, const CMidiPacket &b); // operator< for testing less_than for MidiPackets friend bool operator<(const CMidiPacket &a, const CMidiPacket &b); /****************************** END FRIENDS ******************************/
Assignment 3.1.2
Implement these friend functions in hw312_CMidiPacket.cpp
- std::ostream &operator<<(std::ostream &os, const CMidiPacket &mp)
- std::istream &operator>>(std::istream &is, CMidiPacket &mp)
- bool operator==(const CMidiPacket &a, const CMidiPacket &b)
We'll leave operator< (less) for next time. It's complicated.
Output before implementing friends
===> test output operator<<() # You need to write operator<< You need to write operator<< oss.str(): # --------------------------- ===> test input operator >>() from a istringstream You need to write operator>> You need to write operator<< # --------------------------- ===> test_operator_equals a: You need to write operator<< b: You need to write operator<< c: You need to write operator<< d: You need to write operator<< a == b You need to write operator== false a == c You need to write operator== false d == b You need to write operator== false # ---------------------------
Output after implementing friends
===> test output operator<<() # 100 90 60 100 oss.str(): 100 90 60 100 # --------------------------- ===> test input operator >>() from a istringstream 100 90 60 100 # --------------------------- ===> test_operator_equals a: 1000 90 60 100 b: 1000 90 60 100 c: 1000 80 60 0 d: 1000 c0 11 a == b true a == c false d == b false # ---------------------------
Submission Format
Feel free to email jellinge@carleton.edu on any part of the homework that is unclear to you. Chances are if you have questions other students do too. I will answer those questions by email to everyone in the class. The original sender will remain anonymous. I have tried to provide clues to the homework in the web pages, reading assignments, and labs. Sometimes what seems obvious to me is not obvious to students just learning C++.
Create a folder named hwNN_LastnameFirstname1_LastnameFirstname2.
Substitute your name and your partner's name for LastnameFirstname1_LastnameFirstname2.
Remember
- Boilerplate header at top of every file.
- Make sure your program compiles before submitting.
- Programs that compile and produce partially correct output will be graded.
- You can send notes to me in your homework files by enclosing them in block comments.
- Programs that do not compile get an automatic F (59%).
- Each partner must submit identical homework folders to the course Hand-in folder.
- If only one partner submits the homework send me an email explaining why.
- Empty your build or build-debug folders using the command emptyBuildFolder.sh
- Only include .h, .cpp, Makefiles, CMakeLists.txt
- Do not include these folders/files
.git
.vscode Double check for the above two folders using this command
ls -a hwNN_LastnameFirstname1_LastnameFirstname2 # if either .git or .vscode exist in the folder you're submitting remove them with # rm -fR .git # rm -fR .vscode
Contents hw31_LastnameFirstname1_LastnameFirstname2
/hw31_LastnameFirstname1_LastnameFirstname2 ├── hw311_regex │ ├── hw311_answer.txt │ └── oldDatabase.txt └── hw312_CMidiPacketFriends ├── CMakeLists.txt ├── build ├── hw312_CMidiPacket.cpp ├── hw312_CMidiPacket.h ├── hw312_main.cpp ├── hw312_test_CMidiPacket.cpp └── hw312_test_CMidiPacket.h