The first argument is the pattern (iPhone|iPad). It either matches the first part right in front of the or symbol |—which is iPhone—or the second part after it—which is iPad.
The second argument is the text 'Buy now: iPhone only $399 with free iPad' which you want to search for the pattern.
The result shows that there are two matching substrings in the text: 'iPhone' and 'iPad'.
Python Regex Or: Examples
Let’s study some more examples to teach you all the possible uses and border cases—one after another.
You start with the previous example:
>>> import re
>>> text = 'Buy now: iPhone only $399 with free iPad'
>>> re.findall('(iPhone|iPad)', text)
['iPhone', 'iPad']
In the second example, you just skipped the parentheses using the regex pattern iPhone|iPad rather than (iPhone|iPad). But no problem–it still works and generates the exact same output!
But what happens if you leave one side of the or operation empty?
The output is not as strange as it seems. The or operator allows for empty operands—in which case it wants to match the non-empty string. If this is not possible, it matches the empty string (so everything will be a match).
The previous example also shows that it still tries to match the non-empty string if possible. But what if the trivial empty match is on the left side of the or operand?
This shows some subtleties of the regex engine. First of all, it still matches the non-empty string if possible! But more importantly, you can see that the regex engine matches from left to right. It first tries to match the left regex (which it does on every single position in the text). An empty string that’s already matched will not be considered anymore. Only then, it tries to match the regex on the right side of the or operator.
Think of it this way: the regex engine moves from the left to the right—one position at a time. It matches the empty string every single time. Then it moves over the empty string and in some cases, it can still match the non-empty string. Each match “consumes” a substring and cannot be matched anymore. But an empty string cannot be consumed. That’s why you see the first match is the empty string and the second match is the substring 'iPhone'.
How to Nest the Python Regex Or Operator?
Okay, you’re not easily satisfied, are you? Let’s try nesting the Python regex or operator |.
>>> text = 'xxx iii zzz iii ii xxx'
>>> re.findall('xxx|iii|zzz', text)
['xxx', 'iii', 'zzz', 'iii', 'xxx']
So you can use multiple or operators in a row. Of course, you can also use the grouping (parentheses) operator to nest an arbitrary complicated construct of or operations:
But this seldomly leads to clean and readable code. And it can usually avoided easily by putting a bit of thought into your regex design.
Python Regex Or: Character Class
If you only want to match a single character out of a set of characters, the character class is a much better way of doing it:
>>> import re
>>> text = 'hello world'
>>> re.findall('[abcdefghijklmnopqrstuvwxyz]+', text)
['hello', 'world']
A shorter and more concise version would be to use the range operator within character classes:
>>> re.findall('[a-z]+', text)
['hello', 'world']
The character class is enclosed in the bracket notation [ ] and it literally means “match exactly one of the symbols in the class”. Thus, it carries the same semantics as the or operator: |. However, if you try to do something on those lines…
… you’ll first write much less concise code and, second, risk of getting confused by the output. The reason is that the parenthesis is the group operator—it captures the position and substring that matches the regex. Used in the findall() method, it only returns the content of the last matched group. This turns out to be the last character of the word 'hello' and the last character of the word 'world'.
How to Match the Or Character (Vertical Line ‘|’)?
So if the character '|' stands for the or character in a given regex, the question arises how to match the vertical line symbol '|' itself?
The answer is simple: escape the or character in your regular expression using the backslash. In particular, use 'A\|B' instead of 'A|B' to match the string 'A|B' itself. Here’s an example:
Do you really understand the outputs of this code snippet? In the first example, you’re searching for either character 'A' or character 'B'. In the second example, you’re searching for the string 'A|B' (which contains the '|' character).
Python Regex And
If there’s a Python regex “or”, there must also be an “and” operator, right?
Correct! But think about it for a moment: say, you want one regex to occur alongside another regex. In other words, you want to match regex A and regex B. So what do you do? You match regex AB.
You’ve already seen many examples of the “Python regex AND” operator—but here’s another one:
>>> import re
>>> re.findall('AB', 'AAAACAACAABAAAABAAC')
['AB', 'AB']
The simple concatenation of regex A and B already performs an implicit “and operation”.
Python Regex Not
How can you search a string for substrings that do NOT match a given pattern? In other words, what’s the “negative pattern” in Python regular expressions?
The answer is two-fold:
If you want to match all characters except a set of specific characters, you can use the negative character class [^...].
If you want to match all substrings except the ones that match a regex pattern, you can use the feature of negative lookahead(?!...).
Here’s an example for the negative character class:
>>> import re
>>> re.findall('[^a-m]', 'aaabbbaababmmmnoopmmaa')
['n', 'o', 'o', 'p']
And here’s an example for the negative lookahead pattern to match all “words that are not followed by words”:
The negative lookahead (?![a-z]+) doesn’t consume (match) any character. It just checks whether the pattern [a-z]+ does NOT match at a given position. The only times this happens is just before the empty space and the end of the string.
[Collection] What Are The Different Python Re Quantifiers?
The “and”, “or”, and “not” operators are not the only regular expression operators you need to understand. So what are other operators?
Next, you’ll get a quick and dirty overview of the most important regex operations and how to use them in Python. Here are the most important regex quantifiers:
Quantifier
Description
Example
.
The wild-card (‘dot’) matches any character in a string except the newline character ‘n’.
Regex ‘…’ matches all words with three characters such as ‘abc’, ‘cat’, and ‘dog’.
*
The zero-or-more asterisk matches an arbitrary number of occurrences (including zero occurrences) of the immediately preceding regex.
Regex ‘cat*’ matches the strings ‘ca’, ‘cat’, ‘catt’, ‘cattt’, and ‘catttttttt’.
?
The zero-or-one matches (as the name suggests) either zero or one occurrences of the immediately preceding regex.
Regex ‘cat?’ matches both strings ‘ca’ and ‘cat’ — but not ‘catt’, ‘cattt’, and ‘catttttttt’.
+
The at-least-one matches one or more occurrences of the immediately preceding regex.
Regex ‘cat+’ does not match the string ‘ca’ but matches all strings with at least one trailing character ‘t’ such as ‘cat’, ‘catt’, and ‘cattt’.
^
The start-of-string matches the beginning of a string.
Regex ‘^p’ matches the strings ‘python’ and ‘programming’ but not ‘lisp’ and ‘spying’ where the character ‘p’ does not occur at the start of the string.
$
The end-of-string matches the end of a string.
Regex ‘py$’ would match the strings ‘main.py’ and ‘pypy’ but not the strings ‘python’ and ‘pypi’.
A|B
The OR matches either the regex A or the regex B. Note that the intuition is quite different from the standard interpretation of the or operator that can also satisfy both conditions.
Regex ‘(hello)|(hi)’ matches strings ‘hello world’ and ‘hi python’. It wouldn’t make sense to try to match both of them at the same time.
AB
The AND matches first the regex A and second the regex B, in this sequence.
We’ve already seen it trivially in the regex ‘ca’ that matches first regex ‘c’ and second regex ‘a’.
Note that I gave the above operators some more meaningful names (in bold) so that you can immediately grasp the purpose of each regex. For example, the ‘^’ operator is usually denoted as the ‘caret’ operator. Those names are not descriptive so I came up with more kindergarten-like words such as the “start-of-string” operator.
We’ve already seen many examples but let’s dive into even more!
import re text = ''' Ha! let me see her: out, alas! he's cold: Her blood is settled, and her joints are stiff; Life and these lips have long been separated: Death lies on her like an untimely frost Upon the sweetest flower of all the field. ''' print(re.findall('.a!', text)) '''
Finds all occurrences of an arbitrary character that is
followed by the character sequence 'a!'.
['Ha!'] ''' print(re.findall('is.*and', text)) '''
Finds all occurrences of the word 'is',
followed by an arbitrary number of characters
and the word 'and'.
['is settled, and'] ''' print(re.findall('her:?', text)) '''
Finds all occurrences of the word 'her',
followed by zero or one occurrences of the colon ':'.
['her:', 'her', 'her'] ''' print(re.findall('her:+', text)) '''
Finds all occurrences of the word 'her',
followed by one or more occurrences of the colon ':'.
['her:'] ''' print(re.findall('^Ha.*', text)) '''
Finds all occurrences where the string starts with
the character sequence 'Ha', followed by an arbitrary
number of characters except for the new-line character. Can you figure out why Python doesn't find any?
[] ''' print(re.findall('n$', text)) '''
Finds all occurrences where the new-line character 'n'
occurs at the end of the string.
['n'] ''' print(re.findall('(Life|Death)', text)) '''
Finds all occurrences of either the word 'Life' or the
word 'Death'.
['Life', 'Death'] '''
In these examples, you’ve already seen the special symbol ‘\n’ which denotes the new-line character in Python (and most other languages). There are many special characters, specifically designed for regular expressions. Next, we’ll discover the most important special symbols.
Related Re Methods
There are seven important regular expression methods which you must master:
The re.findall(pattern, string) method returns a list of string matches. Read more in our blog tutorial.
The re.search(pattern, string) method returns a match object of the first match. Read more in our blog tutorial.
The re.match(pattern, string) method returns a match object if the regex matches at the beginning of the string. Read more in our blog tutorial.
The re.fullmatch(pattern, string) method returns a match object if the regex matches the whole string. Read more in our blog tutorial.
The re.compile(pattern) method prepares the regular expression pattern—and returns a regex object which you can use multiple times in your code. Read more in our blog tutorial.
The re.split(pattern, string) method returns a list of strings by matching all occurrences of the pattern in the string and dividing the string along those. Read more in our blog tutorial.
The re.sub(The re.sub(pattern, repl, string, count=0, flags=0) method returns a new string where all occurrences of the pattern in the old string are replaced by repl. Read more in our blog tutorial.
These seven methods are 80% of what you need to know to get started with Python’s regular expression functionality.
Where to Go From Here?
You’ve learned everything you need to know about the Python Regex Or Operator.
Summary:
Given a string. Say, your goal is to find all substrings that match either the string 'iPhone' or the string 'iPad'. How can you achieve this?
The easiest way to achieve this is the Python or operator | using the regular expression pattern (iPhone|iPad).
Want to earn money while you learn Python? Average Python programmers earn more than $50 per hour. You can certainly become average, can’t you?
Join the free webinar that shows you how to become a thriving coding business owner online!
How do you know your readers’ or customers’ thoughts on your website content? How does the star rating feature help to collect customers’ opinions?
Star rating is a feature that is used across different domains in a variety of ways. For example, it is one of the key building blocks in an eCommerce website.
Star rating helps you to know how people rank your content. It not only gives rank on your content. Also, it brings more readers to your page by the gained rating.
When you build a website, if you have got scope for implementing a star rating system and you should definitely experiment with it.
Websites use a variety of ways to allow users to rate content. For example, star rating, up-down rating, emoji rating and more.
We have seen so many examples for star rating, emoji rating and more. I grouped all those in this one single example.
I supported three UI alternatives for the rating section. Those are,
Five-star rating
Favorite rating
Emoji rating
I created a directive in PHP to configure the template for the rating appearance.
Existing plugins to implement a dynamic star rating
There are various plugins available in the market to enable star rating. The ready-made plugins are with enormous features.
For example, Rateit is a jQuery based star rating plugin. It allows embedding a star rating with a list, select and more HTML markup. It supports Font Awesome, Material icons to display rating icons.
The UpvoteJS is a JavaScript package to render a StackExchange-like rating widget.
If you are having a WordPress website, there are built-in rating plugins available. Wp-PostRatings is a popular plugin to implement rating.
Advantages of creating a custom star rating script
With a custom star rating, we can simplify the code logic instead of stuffing a lot.
And thereby, it will make it easy at the time of enhancement or maintenance phase.
It rectifies your overload with a feature-packed built-in. Also, it reduces your effort on managing a thousand lines of code for this simple UI feature.
Various types of rating options
Websites use a different type of rating options to get user’s reviews. The following list shows some of the types.
Single or multiple star rating
Facebook-like emoji rating
Simple up-down voting.
Like-unlike rating
Bar rating
The types are veries in user’s mindset while rating. For example, the like-unlike and up-down rating expects binary options 0 or 1 from the user. But with the bar rating, it can have a range of points out of some limit.
Star rating example with AJAX
I have created an AJAX-based star rating example code with PHP and jQuery.
This code will show a list of courses with an option to rate each course. The courses are from the database.
The rating element in the UI is configurable. I provided three UI alternatives for the rating section. Star, favorite and emoji ratings are there to collect users’ reviews.
While adding the rating, the code sends it to the PHP via AJAX. Then, it saves the ratings in the MySQL database.
Once rated, the user cannot rerate a course again to avoid duplicate ratings.
The following figure shows the file strucuture of the example code.
The rating example database
This section shows the structure and the SQL of the database used in this example.
I have created two tables tbl_courses and tbl_course_rating. The tbl_cources database table contains courses on which the user will add ratings.
The tbl_cource_rating table has the mapping with the tbl_cource database. It has a unique rating without duplicates.
The below script shows the CREATE statement and the data dump for these two tables. By importing this script, you can setup this example in the local environment.
sql/db_rating.sql
--
-- Database: `db_rating`
-- -- -------------------------------------------------------- --
-- Table structure for table `tbl_course`
-- CREATE TABLE `tbl_course` ( `id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `description` varchar(255) NOT NULL, `period` varchar(255) NOT NULL, `availabe_seats` int(11) NOT NULL, `last_date_to_register` date NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1; --
-- Dumping data for table `tbl_course`
-- INSERT INTO `tbl_course` (`id`, `name`, `description`, `period`, `availabe_seats`, `last_date_to_register`) VALUES
(1, 'Professional Training for Finantial Analyst\r\n', 'Professional Training for Finantial Analyst', '30 days', 2, '2020-01-31'),
(2, 'Enterprise Programming in Artificial Intelligence\r\n', 'Enterprise Programming in Artificial Intelligence', '30 days', 2, '2020-01-24'); -- -------------------------------------------------------- --
-- Table structure for table `tbl_course_rating`
-- CREATE TABLE `tbl_course_rating` ( `id` int(11) NOT NULL, `course_id` int(11) NOT NULL, `member_id` int(11) NOT NULL, `rating` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1; --
-- Indexes for dumped tables
-- --
-- Indexes for table `tbl_course`
--
ALTER TABLE `tbl_course` ADD PRIMARY KEY (`id`); --
-- Indexes for table `tbl_course_rating`
--
ALTER TABLE `tbl_course_rating` ADD PRIMARY KEY (`id`); --
-- AUTO_INCREMENT for dumped tables
-- --
-- AUTO_INCREMENT for table `tbl_course`
--
ALTER TABLE `tbl_course` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=3; --
-- AUTO_INCREMENT for table `tbl_course_rating`
--
ALTER TABLE `tbl_course_rating` MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=95;
COMMIT;
UI design to render star rating option
In a landing page, it shows the list of courses from the database. The HTML code for this page is below.
It loads the rating element based on the PHP constant defined in a common configuration file.
The rating element will show clickable 5-stars or favorite-icons or emoji icons.
On clicking the rating element, it invokes a jQuery script to send AJAX requests to save ratings.
I created separate template files to have different types of rating UI. Those are star-rating-view.php, favorite-rating-view.php and emoji_rating_view.php.
The template files show the onClick event handling specification in the markup.
In the emoji rating template, it shows a range of five emotion icons from very-sad to very-happy.
If you are providing support on the user’s queries, you can use the emoji rating. Embedding the emoji rating will give the customer’s emotional feel on your support.
This file contains jQuery functions to prepare AJAX requests to save user ratings.
It also handles the mouse hover events to highlight the rating element. The mouseOverRating() function highlights the star or other rating elements on hovering.
Similarly, mouseOutRating() resets the rating UI back to its original form on mouse out.
The AJAX code in the addRating() prepares the request with PHP endpoint URL and data params.
It receives the server response in the AJAX success callback at which it updates the UI accordingly.
assets/js/rating.js
function mouseOverRating(courseId, rating, appearance) { if (appearance == "star") { for (var i = 1; i <= rating; i++) { $('#' + courseId + "_" + i + ' img').attr('src', "./img/" + appearance + "-filled.png"); } } else { ratingIconPrefix = "./img/" + appearance; for (var i = 1; i <= rating; i++) { if (appearance == "emoji") { ratingIconPrefix = "./img/" + appearance + "1"; } if (i == rating) { $('#' + courseId + "_" + i + ' img').attr('src', ratingIconPrefix + "-filled.png"); } } } } function mouseOutRating(courseId, userRating, appearance) { var ratingId; if (appearance == "star") { if (userRating != 0) { for (var i = 1; i <= userRating; i++) { $('#' + courseId + "_" + i + ' img').attr('src', "./img/" + appearance + "-filled.png"); } } if (userRating <= 5) { for (var i = (userRating + 1); i <= 5; i++) { $('#' + courseId + "_" + i + ' img').attr('src', "./img/" + appearance + "-open.png"); } } $(".selected img").attr('src', "./img/" + appearance + "-filled.png"); } else { ratingIconPrefix = "./img/" + appearance; if (userRating <= 5) { for (var i = 1; i <= 5; i++) { if (appearance == "emoji") { ratingIconPrefix = "./img/" + appearance + i; } if (userRating == i) { $('#' + courseId + "_" + i + ' img').attr('src', ratingIconPrefix + "-filled.png"); } else { $('#' + courseId + "_" + i + ' img').attr('src', ratingIconPrefix + "-open.png"); } } } var selectedImageSource = $(".selected img").attr('src'); if (selectedImageSource) { selectedImageSource = selectedImageSource.replace('open', "filled"); $(".selected img").attr('src', selectedImageSource); } } } function addRating(currentElement, courseId, ratingValue, appearance) { var loaderIcon = $(currentElement).closest(".row-item"); $.ajax({ url : "ajax-end-point/insertRating.php", data : "index=" + ratingValue + "&course_id=" + courseId, type : "POST", beforeSend : function() { $(loaderIcon).find("#loader-icon").show(); }, success : function(data) { loaderIcon = $(currentElement).closest(".row-item"); $(loaderIcon).find("#loader-icon").hide(); if (data != "") { $('#response-' + courseId).text(data); return false; } if (appearance == 'star') { $('#list-' + courseId + ' li').each( function(index) { $(this).addClass('selected'); if (index == $('#list-' + courseId + ' li').index( currentElement)) { return false; } }); } else { $(currentElement).addClass('selected'); } } }); }
Storing user rating to MySQL database from PHP
When the AJAX script called, it prepares a request to the PHP. In PHP, it receives the chosen rating post data and stores it in the rating database.
Though the UI displays different elements, the rating value ranges from 1 to 5. In the database, it has the mapping between the rating value, course id and member id.
The below configuration is for setting the rating element appearance. The possible values are there with a comment statement.
Common/Config.php
<?php
namespace Phppot; class Config
{ // Possible values: star | favourite | emoji const RATING_APPEARANCE = "favourite";
}
Before insert, it checks if the user added a rating already for that particular course. If so, then the code will not allow the user to rate again.
ajax-end-point/insertRating.php
<?php
namespace Phppot; use Phppot\Rating;
require_once __DIR__ . "./../Model/Rating.php";
$rating = new Rating();
// Here the user id is harcoded.
// You can integrate your authentication code here to get the logged in user id
$userId = 5; if (isset($_POST["index"], $_POST["course_id"])) { $courseId = $_POST["course_id"]; $ratingIndex = $_POST["index"]; $rowCount = $rating->isUserRatingExist($userId, $courseId); if ($rowCount == 0) { $insertId = $rating->addRating($userId, $courseId, $ratingIndex); if (empty($insertId)) { echo "Problem in adding ratings."; } } else { echo "You have added rating already."; }
}
This file displays the courses list with the rating option in a landing page.
getRatingData.php
<?php
namespace Phppot; use Phppot\Rating;
require_once "./Common/Config.php";
$config = new Config();
require_once "./Model/Rating.php";
$rating = new Rating();
// Here the user id is harcoded.
// You can integrate your authentication code here to get the logged in user id
$userId = 5; $apperance = $config::RATING_APPEARANCE; $courseResult = $rating->getCourse();
if (! empty($courseResult)) { foreach ($courseResult as $row) { $userRating = $rating->getUserRating($userId, $row['id']); $totalRating = $rating->getTotalRating($row['id']); $date = date_create($row["last_date_to_register"]); ?>
<div class="row-item"> <div class="row-title"><?php echo $row['name']; ?></div> <ul class="list-inline" id="list-<?php echo $row['id']; ?>"> <?php require $apperance . "-rating-view.php"; ?> <img src="img/loader.gif" class="loader-icon" id="loader-icon"> </ul> <div class="response" id="response-<?php echo $row['id']; ?>"></div> <p class="review-note">Total Reviews: <?php echo $totalRating; ?></p> <p class="text-address"> <label class="course-detail">Period: <?php echo $row["period"]; ?></label><label class="course-detail">Available seats: <?php echo $row["availabe_seats"]; ?></label><label class="course-detail">Last Date to Register: <?php echo date_format($date, "d M Y"); ?></label> </p>
</div>
<?php }
}
?>
In the above two PHP files, I have harcoded the user id with a PHP variable $userId. You can plugin user authentication code and get the logged-in user id.
The Rating.php is a PHP model class created for performing the rating actions.
It has functions to read courses and user ratings on them. The getUserRating() and getTotalRating() functions returns data to display the rating statistics.
The isUserRatingExist() checks the uniqueness of the user rating on a particular course.
I used prepared statements with MySQLi for executing the database queries. The source contains a generic DAO class DataSource.php for executing database operations.
Model/Rating.php
<?php
namespace Phppot; use Phppot\DataSource; class Rating
{ private $ds; function __construct() { require_once __DIR__ . './../lib/DataSource.php'; $this->ds = new DataSource(); } function getCourse() { $query = "SELECT * FROM tbl_course ORDER BY id DESC"; $result = $this->ds->select($query); return $result; } function getUserRating($userId, $courseId) { $average = 0; $avgQuery = "SELECT rating FROM tbl_course_rating WHERE member_id = ? and course_id = ?"; $paramType = 'ii'; $paramValue = array( $userId, $courseId ); $result = $this->ds->select($avgQuery, $paramType, $paramValue); if ($result > 0) { foreach ($result as $row) { $average = round($row["rating"]); } // endForeach } // endIf return $average; } function getTotalRating($courseId) { $totalVotesQuery = "SELECT * FROM tbl_course_rating WHERE course_id = ?"; $paramType = 'i'; $paramValue = array( $courseId ); $result = $this->ds->getRecordCount($totalVotesQuery, $paramType, $paramValue); return $result; } function isUserRatingExist($userId, $courseId) { $checkIfExistQuery = "select * from tbl_course_rating where member_id = ? and course_id = ?"; $userId; $courseId; $paramType = 'ii'; $paramValue = array( $userId, $courseId ); $rowCount = $this->ds->getRecordCount($checkIfExistQuery, $paramType, $paramValue); return $rowCount; } function addRating($userId, $courseId, $rating) { $insertQuery = "INSERT INTO tbl_course_rating(member_id,course_id, rating) VALUES (?,?,?) "; $paramType = 'iii'; $paramValue = array( $userId, $courseId, $rating ); $insertId = $this->ds->insert($insertQuery, $paramType, $paramValue); return $insertId; }
}
Output screenshot of different rating options with star, favorite, emoji
In the following screenshot, it displays a text in red. It is an error message to notify the user if he tries to add rating again.
Conclusion
We have seen the importance of implementing a rating script in an application. Also, we have seen the types of ratings generally used by the applications.
By supporting 3 types of rating UI components in an example script, I sure it helps you to have options. You can choose and fix one among them on a need basis.
For example, if you manage more applications, then integrate this one in all. The rating configuration allows setting based on the nature of the application.
There is no limit. We can enhance this component by adding more rating options like-unlike, up-down voting, rating with a ranger and more.
Asset allocation is the process of dividing your portfolio into stocks, bonds, and cash. A famous 1990 study by Kaplan and Ibbotson proves that asset allocation is the most important investment decision for your investment success—far more important than selecting individual securities within the broader asset classes stocks, bonds, and cash.
But what’s the best asset allocation for you?
20% stocks, 50% bonds, 30% cash
50% stocks, 50% bonds
80% stocks, 10% bonds, 10% cash
100% stocks
These different asset allocations have a significant impact on your portfolio risk and return. You must invest most of your time and effort in getting the numbers right.
This is where online tools for asset allocation come into play. They allow you to play with the numbers and see for yourself, based on historical asset class returns, what’s the most sensible investment decision for you.
The best tool for asset allocation comes from my student Ann who just started out with Python and the Python visualization framework Dash. With Python, Dash, and Flask, she has built an incredibly useful tool to help you, as an individual investor, save thousands of dollars of fees paid to investment advisors. And the best thing: it’s 100% free! Check it out.
This article is all about the start of line ^ and end of line $ regular expressions in Python’s re library. These two regexes are fundamental to all regular expressions—even outside the Python world. So invest 5 minutes now and master them once and for all!
Python Re Start-of-String (^) Regex
You can use the caret operator ^ to match the beginning of the string. For example, this is useful if you want to ensure that a pattern appears at the beginning of a string. Here’s an example:
>>> import re
>>> re.findall('^PYTHON', 'PYTHON is fun.')
['PYTHON']
The findall(pattern, string) method finds all occurrences of the pattern in the string. The caret at the beginning of the pattern ‘^PYTHON’ ensures that you match the word Python only at the beginning of the string. In the previous example, this doesn’t make any difference. But in the next example, it does:
>>> re.findall('^PYTHON', 'PYTHON! PYTHON is fun')
['PYTHON']
Although there are two occurrences of the substring ‘PYTHON’, there’s only one matching substring—at the beginning of the string.
But what if you want to match not only at the beginning of the string but at the beginning of each line in a multi-line string? In other words:
Python Re Start-of-Line (^) Regex
The caret operator, per default, only applies to the start of a string. So if you’ve got a multi-line string—for example, when reading a text file—it will still only match once: at the beginning of the string.
However, you may want to match at the beginning of each line. For example, you may want to find all lines that start with ‘Python’ in a given string.
You can specify that the caret operator matches the beginning of each line via the re.MULTILINE flag. Here’s an example showing both usages—without and with setting the re.MULTILINE flag:
>>> import re
>>> text = '''
Python is great.
Python is the fastest growing
major programming language in
the world.
Pythonistas thrive.'''
>>> re.findall('^Python', text)
[]
>>> re.findall('^Python', text, re.MULTILINE)
['Python', 'Python', 'Python']
>>>
The first output is the empty list because the string ‘Python’ does not appear at the beginning of the string.
The second output is the list of three matching substrings because the string ‘Python’ appears three times at the beginning of a line.
Python re.sub()
The re.sub(pattern, repl, string, count=0, flags=0) method returns a new string where all occurrences of the pattern in the old string are replaced by repl. Read more in the Finxter blog tutorial.
You can use the caret operator to substitute wherever some pattern appears at the beginning of the string:
>>> import re
>>> re.sub('^Python', 'Code', 'Python is \nPython') 'Code is \nPython'
Only the beginning of the string matches the regex pattern so you’ve got only one substitution.
Again, you can use the re.MULTILINE flag to match the beginning of each line with the caret operator:
>>> re.sub('^Python', 'Code', 'Python is \nPython', flags=re.MULTILINE) 'Code is \nCode'
Now, you replace both appearances of the string ‘Python’.
Python re.match(), re.search(), re.findall(), and re.fullmatch()
Let’s quickly recap the most important regex methods in Python:
The re.findall(pattern, string, flags=0) method returns a list of string matches. Read more in our blog tutorial.
The re.search(pattern, string, flags=0) method returns a match object of the first match. Read more in our blog tutorial.
The re.match(pattern, string, flags=0) method returns a match object if the regex matches at the beginning of the string. Read more in our blog tutorial.
The re.fullmatch(pattern, string, flags=0) method returns a match object if the regex matches the whole string. Read more in our blog tutorial.
You can see that all four methods search for a pattern in a given string. You can use the caret operator ^ within each pattern to match the beginning of the string. Here’s one example per method:
So you can use the caret operator to match at the beginning of the string. However, you should note that it doesn’t make a lot of sense to use it for the match() and fullmatch() methods as they, by definition, start by trying to match the first character of the string.
You can also use the re.MULTILINE flag to match the beginning of each line (rather than only the beginning of the string):
Again, it’s questionable whether this makes sense for the re.match() and re.fullmatch() methods as they only look for a match at the beginning of the string.
Python Re End of String ($) Regex
Similarly, you can use the dollar-sign operator $ to match the end of the string. Here’s an example:
>>> import re
>>> re.findall('fun$', 'PYTHON is fun')
['fun']
The findall() method finds all occurrences of the pattern in the string—although the trailing dollar-sign $ ensures that the regex matches only at the end of the string.
This can significantly alter the meaning of your regex as you can see in the next example:
>>> re.findall('fun$', 'fun fun fun')
['fun']
Although, there are three occurrences of the substring ‘fun’, there’s only one matching substring—at the end of the string.
But what if you want to match not only at the end of the string but at the end of each line in a multi-line string?
Python Re End of Line ($)
The dollar-sign operator, per default, only applies to the end of a string. So if you’ve got a multi-line string—for example, when reading a text file—it will still only match once: at the end of the string.
However, you may want to match at the end of each line. For example, you may want to find all lines that end with ‘.py’.
To achieve this, you can specify that the dollar-sign operator matches the end of each line via the re.MULTILINE flag. Here’s an example showing both usages—without and with setting the re.MULTILINE flag:
>>> import re
>>> text = '''
Coding is fun
Python is fun
Games are fun
Agreed?'''
>>> re.findall('fun$', text)
[]
>>> re.findall('fun$', text, flags=re.MULTILINE)
['fun', 'fun', 'fun']
>>>
The first output is the empty list because the string ‘fun’ does not appear at the end of the string.
The second output is the list of three matching substrings because the string ‘fun’ appears three times at the end of a line.
Python re.sub()
The re.sub(pattern, repl, string, count=0, flags=0) method returns a new string where all occurrences of the pattern in the old string are replaced by repl. Read more in the Finxter blog tutorial.
You can use the dollar-sign operator to substitute wherever some pattern appears at the end of the string:
>>> import re
>>> re.sub('Python$', 'Code', 'Is Python\nPython') 'Is Python\nCode'
Only the end of the string matches the regex pattern so there’s only one substitution.
Again, you can use the re.MULTILINE flag to match the end of each line with the dollar-sign operator:
Now, you replace both appearances of the string ‘Python’.
Python re.match(), re.search(), re.findall(), and re.fullmatch()
All four methods—re.findall(), re.search(), re.match(), and re.fullmatch()—search for a pattern in a given string. You can use the dollar-sign operator $ within each pattern to match the end of the string. Here’s one example per method:
>>> import re
>>> text = 'Python is Python'
>>> re.findall('Python$', text)
['Python']
>>> re.search('Python$', text)
<re.Match object; span=(10, 16), match='Python'>
>>> re.match('Python$', text)
>>> re.fullmatch('Python$', text)
>>>
So you can use the dollar-sign operator to match at the end of the string. However, you should note that it doesn’t make a lot of sense to use it for the fullmatch() methods as it, by definition, already requires that the last character of the string is part of the matching substring.
You can also use the re.MULTILINE flag to match the end of each line (rather than only the end of the whole string):
As the pattern doesn’t match the string prefix, both re.match() and re.fullmatch() return empty results.
How to Match the Caret (^) or Dollar ($) Symbols in Your Regex?
You know that the caret and dollar symbols have a special meaning in Python’s regular expression module: they match the beginning or end of each string/line. But what if you search for the caret (^) or dollar ($) symbols themselves? How can you match them in a string?
The answer is simple: escape the caret or dollar symbols in your regular expression using the backslash. In particular, use ‘\^’ instead of ‘^’ and ‘\$’ instead of ‘$’. Here’s an example:
>>> import re
>>> text = 'The product ^^^ costs $3 today.'
>>> re.findall('\^', text)
['^', '^', '^']
>>> re.findall('\$', text)
['$']
By escaping the special symbols ^ and $, you tell the regex engine to ignore their special meaning.
Where to Go From Here?
You’ve learned everything you need to know about the caret operator ^ and the dollar-sign operator $ in this regex tutorial.
Summary: The caret operator ^ matches at the beginning of a string. The dollar-sign operator $ matches at the end of a string. If you want to match at the beginning or end of each line in a multi-line string, you can set the re.MULTILINE flag in all the relevant re methods.
Want to earn money while you learn Python? Average Python programmers earn more than $50 per hour. You can become average, can’t you?
Join the free webinar that shows you how to become a thriving coding business owner online!
This article is all about the plus “+” symbol in Python’s re library. Study it carefully and master this important piece of knowledge once and for all!
What’s the Python Re + Quantifier?
Say, you have any regular expression A. The regular expression (regex) A+ then matches one or more occurrences of A. We call the “+” symbol the at-least-once quantifier because it requires at least one occurrence of the preceding regex. For example, the regular expression ‘yes+’ matches strings ‘yes’, ‘yess’, and ‘yesssssss’. But it does neither match the string ‘ye’, nor the empty string ” because the plus quantifier + does not apply to the whole regex ‘yes’ but only to the preceding regex ‘s’.
Let’s study some examples to help you gain a deeper understanding.
The first argument is the regular expression pattern ‘a+b’ and the second argument is the string to be searched. In plain English, you want to find all patterns in the string that start with at least one, but possibly many, characters ‘a’, followed by the character ‘b’.
The findall() method returns the matching substring: ‘aaaaaab’. The asterisk quantifier + is greedy. This means that it tries to match as many occurrences of the preceding regex as possible. So in our case, it wants to match as many arbitrary characters as possible so that the pattern is still matched. Therefore, the regex engine “consumes” the whole sentence.
The second example is similar:
>>> re.findall('ab+', 'aaaaaabb')
['abb']
You search for the character ‘a’ followed by at least one character ‘b’. As the plus (+) quantifier is greedy, it matches as many ‘b’s as it can lay its hands on.
Examples 3 and 4: Non-Greedy Plus (+) Quantifiers
But what if you want to match at least one occurrence of a regex in a non-greedy manner. In other words, you don’t want the regex engine to consume more and more as long as it can but returns as quickly as it can from the processing.
Again, here’s the example of the greedy match:
>>> re.findall('ab+', 'aaaaaabbbbb')
['abbbbb']
The regex engine starts with the first character ‘a’ and finds that it’s a partial match. So, it moves on to match the second ‘a’—which violates the pattern ‘ab+’ that allows only for a single character ‘a’. So it moves on to the third character, and so on, until it reaches the last character ‘a’ in the string ‘aaaaaabbbbb’. It’s a partial match, so it moves on to the first occurrence of the character ‘b’. It realizes that the ‘b’ character can be matched by the part of the regex ‘b+’. Thus, the engine starts matching ‘b’s. And it greedily matches ‘b’s until it cannot match any further character. At this point it looks at the result and sees that it has found a matching substring which is the result of the operation.
However, it could have stopped far earlier to produce a non-greedy match after matching the first character ‘b’. Here’s an example of the non-greedy quantifier ‘+?’ (both symbols together form one regex expression).
>>> re.findall('ab+?', 'aaaaaabbbbb')
['ab']
Now, the regex engine does not greedily “consume” as many ‘b’ characters as possible. Instead, it stops as soon as the pattern is matched (non-greedy).
Examples 5 and 6
For the sake of your thorough understanding, let’s have a look at the other given example:
>>> re.findall('ab+', 'aaaaaa')
[]
You can see that the plus (+) quantifier requires that at least one occurrence of the preceding regex is matched. In the example, it’s the character ‘b’ that is not partially matched. So, the result is the empty list indicating that no matching substring was found.
You use the plus (+) quantifier in combination with a character class that defines specifically which characters are valid matches.
Note Character Class: Within the character class, you can define character ranges. For example, the character range [a-z] matches one lowercase character in the alphabet while the character range [A-Z] matches one uppercase character in the alphabet.
The empty space is not part of the given character class [a-z], so it won’t be matched in the text. Thus, the result is the list of words that start with at least one character: ‘hello’, ‘world’.
What If You Want to Match the Plus (+) Symbol Itself?
You know that the plus quantifier matches at least one of the preceding regular expression. But what if you search for the plus (+) symbol itself? How can you search for it in a string?
The answer is simple: escape the plus symbol in your regular expression using the backslash. In particular, use ‘\+’ instead of ‘+’. Here’s an example:
If you want to find the ‘+’ symbol in your string, you need to escape it by using the backslash. If you don’t do this, the Python regex engine will interpret it as a normal “at-least-once” regex. Of course, you can combine the escaped plus symbol ‘\+’ with the “at-least-once” regex searching for at least one occurrences of the plus symbol.
[Collection] What Are The Different Python Re Quantifiers?
The plus quantifier—Python re +—is only one of many regex operators. If you want to use (and understand) regular expressions in practice, you’ll need to know all of them by heart!
So let’s dive into the other operators:
A regular expression is a decades-old concept in computer science. Invented in the 1950s by famous mathematician Stephen Cole Kleene, the decades of evolution brought a huge variety of operations. Collecting all operations and writing up a comprehensive list would result in a very thick and unreadable book by itself.
Fortunately, you don’t have to learn all regular expressions before you can start using them in your practical code projects. Next, you’ll get a quick and dirty overview of the most important regex operations and how to use them in Python. In follow-up chapters, you’ll then study them in detail — with many practical applications and code puzzles.
Here are the most important regex quantifiers:
Quantifier
Description
Example
.
The wild-card (‘dot’) matches any character in a string except the newline character ‘n’.
Regex ‘…’ matches all words with three characters such as ‘abc’, ‘cat’, and ‘dog’.
*
The zero-or-more asterisk matches an arbitrary number of occurrences (including zero occurrences) of the immediately preceding regex.
Regex ‘cat*’ matches the strings ‘ca’, ‘cat’, ‘catt’, ‘cattt’, and ‘catttttttt’.
?
The zero-or-one matches (as the name suggests) either zero or one occurrences of the immediately preceding regex.
Regex ‘cat?’ matches both strings ‘ca’ and ‘cat’ — but not ‘catt’, ‘cattt’, and ‘catttttttt’.
+
The at-least-one matches one or more occurrences of the immediately preceding regex.
Regex ‘cat+’ does not match the string ‘ca’ but matches all strings with at least one trailing character ‘t’ such as ‘cat’, ‘catt’, and ‘cattt’.
^
The start-of-string matches the beginning of a string.
Regex ‘^p’ matches the strings ‘python’ and ‘programming’ but not ‘lisp’ and ‘spying’ where the character ‘p’ does not occur at the start of the string.
$
The end-of-string matches the end of a string.
Regex ‘py$’ would match the strings ‘main.py’ and ‘pypy’ but not the strings ‘python’ and ‘pypi’.
A|B
The OR matches either the regex A or the regex B. Note that the intuition is quite different from the standard interpretation of the or operator that can also satisfy both conditions.
Regex ‘(hello)|(hi)’ matches strings ‘hello world’ and ‘hi python’. It wouldn’t make sense to try to match both of them at the same time.
AB
The AND matches first the regex A and second the regex B, in this sequence.
We’ve already seen it trivially in the regex ‘ca’ that matches first regex ‘c’ and second regex ‘a’.
Note that I gave the above operators some more meaningful names (in bold) so that you can immediately grasp the purpose of each regex. For example, the ‘^’ operator is usually denoted as the ‘caret’ operator. Those names are not descriptive so I came up with more kindergarten-like words such as the “start-of-string” operator.
We’ve already seen many examples but let’s dive into even more!
import re text = ''' Ha! let me see her: out, alas! he's cold: Her blood is settled, and her joints are stiff; Life and these lips have long been separated: Death lies on her like an untimely frost Upon the sweetest flower of all the field. ''' print(re.findall('.a!', text)) '''
Finds all occurrences of an arbitrary character that is
followed by the character sequence 'a!'.
['Ha!'] ''' print(re.findall('is.*and', text)) '''
Finds all occurrences of the word 'is',
followed by an arbitrary number of characters
and the word 'and'.
['is settled, and'] ''' print(re.findall('her:?', text)) '''
Finds all occurrences of the word 'her',
followed by zero or one occurrences of the colon ':'.
['her:', 'her', 'her'] ''' print(re.findall('her:+', text)) '''
Finds all occurrences of the word 'her',
followed by one or more occurrences of the colon ':'.
['her:'] ''' print(re.findall('^Ha.*', text)) '''
Finds all occurrences where the string starts with
the character sequence 'Ha', followed by an arbitrary
number of characters except for the new-line character. Can you figure out why Python doesn't find any?
[] ''' print(re.findall('n$', text)) '''
Finds all occurrences where the new-line character 'n'
occurs at the end of the string.
['n'] ''' print(re.findall('(Life|Death)', text)) '''
Finds all occurrences of either the word 'Life' or the
word 'Death'.
['Life', 'Death'] '''
In these examples, you’ve already seen the special symbol ‘n’ which denotes the new-line character in Python (and most other languages). There are many special characters, specifically designed for regular expressions. Next, we’ll discover the most important special symbols.
What’s the Difference Between Python Re + and ? Quantifiers?
You can read the Python Re A? quantifier as zero-or-one regex: the preceding regex A is matched either zero times or exactly once. But it’s not matched more often.
Analogously, you can read the Python Re A+ operator as the at-least-once regex: the preceding regex A is matched an arbitrary number of times but at least once (as the name suggests).
The regex ‘ab?’ matches the character ‘a’ in the string, followed by character ‘b’ if it exists (which it does in the code).
The regex ‘ab+’ matches the character ‘a’ in the string, followed by as many characters ‘b’ as possible (and at least one).
What’s the Difference Between Python Re * and + Quantifiers?
You can read the Python Re A* quantifier as zero-or-more regex: the preceding regex A is matched an arbitrary number of times.
Analogously, you can read the Python Re A+ operator as the at-least-once regex: the preceding regex A is matched an arbitrary number of times too—but at least once.
The regex ‘ab*’ matches the character ‘a’ in the string, followed by an arbitary number of occurrences of character ‘b’. The substring ‘a’ perfectly matches this formulation. Therefore, you find that the regex matches eight times in the string.
The regex ‘ab+’ matches the character ‘a’, followed by as many characters ‘b’ as possible—but at least one. However, the character ‘b’ does not exist so there’s no match.
What are Python Re *?, +?, ?? Quantifiers?
You’ve learned about the three quantifiers:
The quantifier A* matches an arbitrary number of patterns A.
The quantifier A+ matches at least one pattern A.
The quantifier A? matches zero-or-one pattern A.
Those three are all greedy: they match as many occurrences of the pattern as possible. Here’s an example that shows their greediness:
The code shows that all three quantifiers *, +, and ? match as many ‘a’ characters as possible.
So, the logical question is: how to match as few as possible? We call this non-greedy matching. You can append the question mark after the respective quantifiers to tell the regex engine that you intend to match as few patterns as possible: *?, +?, and ??.
Here’s the same example but with the non-greedy quantifiers:
In this case, the code shows that all three quantifiers *?, +?, and ?? match as few ‘a’ characters as possible.
Related Re Methods
There are five important regular expression methods which you should master:
The re.findall(pattern, string) method returns a list of string matches. Read more in our blog tutorial.
The re.search(pattern, string) method returns a match object of the first match. Read more in our blog tutorial.
The re.match(pattern, string) method returns a match object if the regex matches at the beginning of the string. Read more in our blog tutorial.
The re.fullmatch(pattern, string) method returns a match object if the regex matches the whole string. Read more in our blog tutorial.
The re.compile(pattern) method prepares the regular expression pattern—and returns a regex object which you can use multiple times in your code. Read more in our blog tutorial.
The re.split(pattern, string) method returns a list of strings by matching all occurrences of the pattern in the string and dividing the string along those. Read more in our blog tutorial.
The re.sub(The re.sub(pattern, repl, string, count=0, flags=0) method returns a new string where all occurrences of the pattern in the old string are replaced by repl. Read more in our blog tutorial.
These seven methods are 80% of what you need to know to get started with Python’s regular expression functionality.
Where to Go From Here?
You’ve learned everything you need to know about the asterisk quantifier * in this regex tutorial.
Summary: Regex A+ matches one or more occurrences of regex A. The “+” symbol is the at-least-once quantifier because it requires at least one occurrence of the preceding regex. The non-greedy version of the at-least-once quantifier is A+? with the trailing question mark.
Want to earn money while you learn Python? Average Python programmers earn more than $50 per hour. You can certainly become average, can’t you?
Join the free webinar that shows you how to become a thriving coding business owner online!
Every computer scientist knows the asterisk quantifier of regular expressions. But many non-techies know it, too. Each time you search for a text file *.txt on your computer, you use the asterisk operator.
This article is all about the asterisk * quantifier in Python’s re library. Study it carefully and master this important piece of knowledge once and for all!
Alternatively, you can also watch the video where I lead you through the whole article:
What’s the Python Re * Quantifier?
When applied to regular expression A, Python’s A* quantifier matches zero or more occurrences of A. The * quantifier is called asterisk operator and it always applies only to the preceding regular expression. For example, the regular expression ‘yes*’ matches strings ‘ye’, ‘yes’, and ‘yesssssss’. But it does not match the empty string because the asterisk quantifier * does not apply to the whole regex ‘yes’ but only to the preceding regex ‘s’.
Let’s study two basic examples to help you gain a deeper understanding. Do you get all of them?
>>> import re
>>> text = 'finxter for fast and fun python learning'
>>> re.findall('f.* ', text)
['finxter for fast and fun python ']
>>> re.findall('f.*? ', text)
['finxter ', 'for ', 'fast ', 'fun ']
>>> re.findall('f[a-z]*', text)
['finxter', 'for', 'fast', 'fun']
>>>
Don’t worry if you had problems understanding those examples. You’ll learn about them next. Here’s the first example:
Greedy Asterisk Example
>>> re.findall('f.* ', text)
['finxter for fast and fun python ']
You use the re.findall() method. In case you don’t know it, here’s the definition from the Finxter blog article:
The re.findall(pattern, string) method finds all occurrences of the pattern in the string and returns a list of all matching substrings.
The first argument is the regular expression pattern ‘f.* ‘. The second argument is the string to be searched for the pattern. In plain English, you want to find all patterns in the string that start with the character ‘f’, followed by an arbitrary number of optional characters, followed by an empty space.
The findall() method returns only one matching substring: ‘finxter for fast and fun python ‘. The asterisk quantifier * is greedy. This means that it tries to match as many occurrences of the preceding regex as possible. So in our case, it wants to match as many arbitrary characters as possible so that the pattern is still matched. Therefore, the regex engine “consumes” the whole sentence.
Non-Greedy Asterisk Example
But what if you want to find all words starting with an ‘f’? In other words: how to match the text with a non-greedy asterisk operator?
In this example, you’re looking at a similar pattern with only one difference: you use the non-greedy asterisk operator *?. You want to find all occurrences of character ‘f’ followed by an arbitrary number of characters (but as few as possible), followed by an empty space.
Therefore, the regex engine finds four matches: the strings ‘finxter ‘, ‘for ‘, ‘fast ‘, and ‘fun ‘.
This regex achieves almost the same thing: finding all words starting with f. But you use the asterisk quantifier in combination with a character class that defines specifically which characters are valid matches.
Within the character class, you can define character ranges. For example, the character range [a-z] matches one lowercase character in the alphabet while the character range [A-Z] matches one uppercase character in the alphabet.
But note that the empty space is not part of the character class, so it won’t be matched if it appears in the text. Thus, the result is the same list of words that start with character f: ‘finxter ‘, ‘for ‘, ‘fast ‘, and ‘fun ‘.
What If You Want to Match the Asterisk Character Itself?
You know that the asterisk quantifier matches an arbitrary number of the preceding regular expression. But what if you search for the asterisk (or star) character itself? How can you search for it in a string?
The answer is simple: escape the asterisk character in your regular expression using the backslash. In particular, use ‘\*’ instead of ‘*’. Here’s an example:
You find all occurrences of the star symbol in the text by using the regex ‘\*’. Consequently, if you use the regex ‘\**’, you search for an arbitrary number of occurrences of the asterisk symbol (including zero occurrences). And if you would like to search for all maximal number of occurrences of subsequent asterisk symbols in a text, you’d use the regex ‘\*+’.
[Collection] What Are The Different Python Re Quantifiers?
The asterisk quantifier—Python re *—is only one of many regex operators. If you want to use (and understand) regular expressions in practice, you’ll need to know all of them by heart!
So let’s dive into the other operators:
A regular expression is a decades-old concept in computer science. Invented in the 1950s by famous mathematician Stephen Cole Kleene, the decades of evolution brought a huge variety of operations. Collecting all operations and writing up a comprehensive list would result in a very thick and unreadable book by itself.
Fortunately, you don’t have to learn all regular expressions before you can start using them in your practical code projects. Next, you’ll get a quick and dirty overview of the most important regex operations and how to use them in Python. In follow-up chapters, you’ll then study them in detail — with many practical applications and code puzzles.
Here are the most important regex quantifiers:
Quantifier
Description
Example
.
The wild-card (‘dot’) matches any character in a string except the newline character ‘n’.
Regex ‘…’ matches all words with three characters such as ‘abc’, ‘cat’, and ‘dog’.
*
The zero-or-more asterisk matches an arbitrary number of occurrences (including zero occurrences) of the immediately preceding regex.
Regex ‘cat*’ matches the strings ‘ca’, ‘cat’, ‘catt’, ‘cattt’, and ‘catttttttt’.
?
The zero-or-one matches (as the name suggests) either zero or one occurrences of the immediately preceding regex.
Regex ‘cat?’ matches both strings ‘ca’ and ‘cat’ — but not ‘catt’, ‘cattt’, and ‘catttttttt’.
+
The at-least-one matches one or more occurrences of the immediately preceding regex.
Regex ‘cat+’ does not match the string ‘ca’ but matches all strings with at least one trailing character ‘t’ such as ‘cat’, ‘catt’, and ‘cattt’.
^
The start-of-string matches the beginning of a string.
Regex ‘^p’ matches the strings ‘python’ and ‘programming’ but not ‘lisp’ and ‘spying’ where the character ‘p’ does not occur at the start of the string.
$
The end-of-string matches the end of a string.
Regex ‘py$’ would match the strings ‘main.py’ and ‘pypy’ but not the strings ‘python’ and ‘pypi’.
A|B
The OR matches either the regex A or the regex B. Note that the intuition is quite different from the standard interpretation of the or operator that can also satisfy both conditions.
Regex ‘(hello)|(hi)’ matches strings ‘hello world’ and ‘hi python’. It wouldn’t make sense to try to match both of them at the same time.
AB
The AND matches first the regex A and second the regex B, in this sequence.
We’ve already seen it trivially in the regex ‘ca’ that matches first regex ‘c’ and second regex ‘a’.
Note that I gave the above operators some more meaningful names (in bold) so that you can immediately grasp the purpose of each regex. For example, the ‘^’ operator is usually denoted as the ‘caret’ operator. Those names are not descriptive so I came up with more kindergarten-like words such as the “start-of-string” operator.
We’ve already seen many examples but let’s dive into even more!
import re text = ''' Ha! let me see her: out, alas! he's cold: Her blood is settled, and her joints are stiff; Life and these lips have long been separated: Death lies on her like an untimely frost Upon the sweetest flower of all the field. ''' print(re.findall('.a!', text)) '''
Finds all occurrences of an arbitrary character that is
followed by the character sequence 'a!'.
['Ha!'] ''' print(re.findall('is.*and', text)) '''
Finds all occurrences of the word 'is',
followed by an arbitrary number of characters
and the word 'and'.
['is settled, and'] ''' print(re.findall('her:?', text)) '''
Finds all occurrences of the word 'her',
followed by zero or one occurrences of the colon ':'.
['her:', 'her', 'her'] ''' print(re.findall('her:+', text)) '''
Finds all occurrences of the word 'her',
followed by one or more occurrences of the colon ':'.
['her:'] ''' print(re.findall('^Ha.*', text)) '''
Finds all occurrences where the string starts with
the character sequence 'Ha', followed by an arbitrary
number of characters except for the new-line character. Can you figure out why Python doesn't find any?
[] ''' print(re.findall('n$', text)) '''
Finds all occurrences where the new-line character 'n'
occurs at the end of the string.
['n'] ''' print(re.findall('(Life|Death)', text)) '''
Finds all occurrences of either the word 'Life' or the
word 'Death'.
['Life', 'Death'] '''
In these examples, you’ve already seen the special symbol ‘\n’ which denotes the new-line character in Python (and most other languages). There are many special characters, specifically designed for regular expressions. Next, we’ll discover the most important special symbols.
What’s the Difference Between Python Re * and ? Quantifiers?
You can read the Python Re A? quantifier as zero-or-one regex: the preceding regex A is matched either zero times or exactly once. But it’s not matched more often.
Analogously, you can read the Python Re A* operator as the zero-or-more regex (I know it sounds a bit clunky): the preceding regex A is matched an arbitrary number of times.
The regex ‘ab?’ matches the character ‘a’ in the string, followed by character ‘b’ if it exists (which it does in the code).
The regex ‘ab*’ matches the character ‘a’ in the string, followed by as many characters ‘b’ as possible.
What’s the Difference Between Python Re * and + Quantifiers?
You can read the Python Re A* quantifier as zero-or-more regex: the preceding regex A is matched an arbitrary number of times.
Analogously, you can read the Python Re A+ operator as the at-least-once regex: the preceding regex A is matched an arbitrary number of times too—but at least once.
The regex ‘ab*’ matches the character ‘a’ in the string, followed by an arbitary number of occurrences of character ‘b’. The substring ‘a’ perfectly matches this formulation. Therefore, you find that the regex matches eight times in the string.
The regex ‘ab+’ matches the character ‘a’, followed by as many characters ‘b’ as possible—but at least one. However, the character ‘b’ does not exist so there’s no match.
What are Python Re *?, +?, ?? Quantifiers?
You’ve learned about the three quantifiers:
The quantifier A* matches an arbitrary number of patterns A.
The quantifier A+ matches at least one pattern A.
The quantifier A? matches zero-or-one pattern A.
Those three are all greedy: they match as many occurrences of the pattern as possible. Here’s an example that shows their greediness:
The code shows that all three quantifiers *, +, and ? match as many ‘a’ characters as possible.
So, the logical question is: how to match as few as possible? We call this non-greedy matching. You can append the question mark after the respective quantifiers to tell the regex engine that you intend to match as few patterns as possible: *?, +?, and ??.
Here’s the same example but with the non-greedy quantifiers:
In this case, the code shows that all three quantifiers *?, +?, and ?? match as few ‘a’ characters as possible.
Related Re Methods
There are five important regular expression methods which you should master:
The re.findall(pattern, string) method returns a list of string matches. Read more in our blog tutorial.
The re.search(pattern, string) method returns a match object of the first match. Read more in our blog tutorial.
The re.match(pattern, string) method returns a match object if the regex matches at the beginning of the string. Read more in our blog tutorial.
The re.fullmatch(pattern, string) method returns a match object if the regex matches the whole string. Read more in our blog tutorial.
The re.compile(pattern) method prepares the regular expression pattern—and returns a regex object which you can use multiple times in your code. Read more in our blog tutorial.
The re.split(pattern, string) method returns a list of strings by matching all occurrences of the pattern in the string and dividing the string along those. Read more in our blog tutorial.
The re.sub(The re.sub(pattern, repl, string, count=0, flags=0) method returns a new string where all occurrences of the pattern in the old string are replaced by repl. Read more in our blog tutorial.
These seven methods are 80% of what you need to know to get started with Python’s regular expression functionality.
Where to Go From Here?
You’ve learned everything you need to know about the asterisk quantifier * in this regex tutorial.
Summary: When applied to regular expression A, Python’s A* quantifier matches zero or more occurrences of A. The * quantifier is called asterisk operator and it always applies only to the preceding regular expression. For example, the regular expression ‘yes*’ matches strings ‘ye’, ‘yes’, and ‘yesssssss’. But it does not match the empty string because the asterisk quantifier * does not apply to the whole regex ‘yes’ but only to the preceding regex ‘s’.
Want to earn money while you learn Python? Average Python programmers earn more than $50 per hour. You can certainly become average, can’t you?
Join the free webinar that shows you how to become a thriving coding business owner online!
What keeps you going day after day? No matter what, you already know that your motivation is the most important building block of your success. In the following, I’d like to give you some fact-based motivation why creating your coding business online can easily be the most rewarding decision in your life.
Yet, motivation is not everything. If you want to make your business work, you must show some persistency. You need to keep working on it for many months, even years.
There’s no quick and easy way to create a successful and lasting business. It takes time, discipline, and focused effort.
The truth is that creating a successful business is a straightforward endeavor if you have the right mindset, habits, and motivation. Using the words of legendary speaker Jim Rohn: “it’s easy to do, but it’s also easy not to do.”
This tutorial intends to give you all the motivation you need to sustain a long time (say, one or two years) working daily on your new online coding business.
You can also watch the video while reading the blog article where I’ll lead you through all the content and more:
In particular, you’ll find an answer to these questions:
Why should you even consider working from home on your online coding business?
What are the advantages?
What are the disadvantages?
What can you expect to happen after you decided not to follow the herd by working for a big corporation or the government?
And, last but not least, what can you expect to earn as a freelance developer?
Let’s take a high-level perspective analyzing some major trends in society.
The Workforce Disruption of the 21st Century
Massive change is the only constant in today’s world. One aspect of those changes is the nature of employment in a globalized economy. It becomes more and more evident that freelancing is the most suitable way of organizing, managing, and delivering talents to small businesses and creators in the 21st century.
Say, you’re a small business owner, and you need to get some editing done for an ebook project. Would you hire a new employee for this project? Or would you just visit an online freelancing platform and hire the best editor you can get for a fair price?
You may find the answer obvious, but I don’t think that most people have already realized the second-order consequences: online freelancing is not a niche idea but has the power to transform and, ultimately, dominate the organization of the world’s talent. It’s accessible to billions of creators and business owners. And it’ll become even more efficient in the future.
When I discuss the evolution of the traditional “job market” to a project-driven “freelancer market”, I often end up debating the ethical implication of this. Yes, it means that there will be less job security in the future. It also means that there will be a massive global competition for skill. The ones who deliver excellent work will get paid much better than their lazy, low-quality competition. You may not like this trend. But this doesn’t mean that it is not happening right now. This tutorial is not about whether we should or should not enter this area. It’s about how you can benefit from this global trend. But to take a stand on this, I find it a highly positive development towards a more efficient workforce where you can simply focus on the work you like, and you’re good at and outsource everything else.
To me, freelancing already is an integral ingredient of my existence. Here’s how freelancing impacts every aspect of my professional life today:
By working as a freelancer myself, I funded and grew my passion online business Finxter.com.
I hire freelancers for Finxter. The more Finxter grows, the more I rely on freelancers to create more value for my users.
I host the most comprehensive Python freelancer course in the world. This is my way of centralizing and sharing (but also learning from) the expertise of professionals across the globe.
My online business would have never been possible in its current form (and scale) without leveraging the efficiency gains of freelancing.
This is great because before freelancing became popular, large corporations practically owned the monopoly for exploiting the benefits of globalized labor.
Today, every small business owner can access the global pool of talents. This way, new arbitrage opportunities open up for every small business owner who seizes them.
Both business owners and freelancers benefit from this trend (as well as the people who, like me, work on both sides).
So how can you benefit from the global freelancing trend? You can benefit by becoming an arbitrage trader: buy and sell freelancing services at the same time! You purchase the services you’re not good at. You sell the services you’re good at. This way, you’re continually increasing your hourly rate. Can you see why? A bit of napkin math will highlight the fundamental arithmetic of outsourcing.
Why Outsourcing is Genius [Alice Example]
Say, you’re a fast coder: you write ten lines of code per minute. But you suck at customer service: you write 0.1 emails per minute. But you need to do both in your current position. To write 100 lines of code and answer ten emails, you need 10 + 100 = 110 minutes. Most of the time, you’ll be answering emails.
Let’s assume further that Alice has the exact opposite preferences: she writes only one line of code per minute (10x slower than you) but answers one email per minute (10x faster than you). To write 100 lines of code and answer ten emails, she’d need 100 + 10 = 110 minutes, too. Most of the time, she’ll be writing code.
Both of you spend most of your time doing work you suck at.
But what if you decide to hire each other? You hire Alice to answer your emails, and Alice hires you to do her coding. Now, you have to write 200 lines of code instead of 100 lines of code which takes you only 20 minutes. Alice now answers 20 emails instead of 10, which takes her 20 minutes. In total, you too finish your work in 20+20=40 minutes instead of 110+110=220 minutes! Together, you saved 220 – 40 = 180 minutes – 3 hours per day!
It’s a stupid idea to do everything by yourself! You’ll leave vast amounts of money on the table if you’re guilty of this.
The freelancer disruption will make the world much more efficient. So let’s get some clarity: is freelancing for you?
Python Freelancer: To Be Or Not To Be?
Becoming a freelancer is an exciting way of growing your business skills, participating in the new economy, learning new technologies, practicing your communication expertise, learning how to sell and market your skills, and earning more and more money on the side. Technology and globalization have opened up this opportunity. And now it’s up to you to seize it.
But what can you expect from this new path of becoming a freelance developer (e.g., focusing on the Python programming language)?
First and foremost, freelancing is a path of personal growth, learning new skills, and earning money in the process. But in today’s digital economy, becoming a Python freelancer is – above everything else – a lifestyle choice. It can give you fulfillment, flexibility, and endless growth opportunities. Additionally, it offers you a unique way of connecting with other people, learning about their exciting projects, and finding friends and acquaintances on the road.
While this sounds nice – becoming a Python freelancer can also be a struggle with the potential to make your life miserable and stressful if you’re approaching it with the wrong strategies and tactics. But no worries, this book is all about teaching you these.
So is being a Python freelancer for you? Let’s discuss the pros and cons of becoming a Python freelancer. The list is based not only on my personal experience as a Python freelancer — working for diverse projects in science, data analytics, and even law enforcement — but I have also assembled the experiences of some of the top experts in the field.
The Good Things
There are many advantages to being a Python freelancer. Here are the most important of them:
Flexibility: You are flexible in time and space. I am living in a large German city (Stuttgart) where rent prices are growing rapidly, year after year. However, since I am working full-time in the Python industry, being self-employed, and 100% digital, I have the freedom to move to the countryside. Outside large cities, housing is exceptionally cheap, and living expenses are genuinely affordable. I am earning good money matched only by a few employees in my home town — while I don’t have to compete for housing to live close to my employers. That’s a huge advantage which can make your life wonderfully peaceful and efficient. Taken to an extreme, you can move to countries with minimal living expenses: earn Dollars and pay Rupees. As a Python freelancer, you are 100% flexible, and this flexibility opens up new possibilities for your life and work.
Independence: Do you hate working for your boss? Being a Python freelancer injects a dose of true independence into your life. While you are not free from influences (after all, you are still working for clients), you can theoretically get rid of any single client while not losing your profession. Firing your bad clients is even a smart thing to do because they demand more of your time, drain your energy, pay you badly (if at all), and don’t value your work in general. In contrast, good clients will treat you with respect, pay well and on time, come back, refer you to other clients, and make working with them a pleasant and productive experience. As an employee, you don’t have this freedom of firing your boss until you find a good one. This is a unique advantage of being a Python freelancer compared to being a Python employee.
Tax advantages: As a freelancer, you start your own business. Please note that I’m not an accountant — and tax laws are different in different countries. But in Germany and many other developed nations, your small Python freelancing business usually comes with a lot of tax advantages. You can deduct a lot of things from the taxes you pay like your Notebook, your car, your living expenses, working environment, eating outside with clients or partners, your smartphone, and so on. At the end of the year, many freelancers enjoy tax benefits worth tens of thousands of dollars.
Business expertise: This advantage is maybe the most important one. As a Python freelancer, you gain a tremendous amount of experience in the business world. You learn to offer and sell your skills in the marketplace, you learn how to acquire clients and keep them happy, you learn how to solve problems, and you learn how to keep your books clean, invest, and manage your money. Being a Python freelancer gives you a lot of valuable business experiences. And even if you plan to start a more scalable business system, being a Python freelancer is a great first step towards your goal.
Paid learning: While you have to pay to learn at University, being a Python freelancer flips this situation upside down. You are getting paid for your education. As a bonus, the things you are learning are as practical as they can be. Instead of coding toy projects in University, you are coding (more or less) exciting projects with an impact on the real world.
Save time in commute: Being in commute is one of the major time killers in modern life. Every morning, people are rushing to their jobs, offices, factories, schools, or universities. Every evening, people are rushing back home. On the way, they leave 1-2 hours of their valuable time on the streets, every single day, 200 days a year. During a ten year period, you’ll waste 2000-4000 hours — enough to become a master in a new topic of your choice, or writing more than ten full books and sell them on the marketplace. Commute time to work is one of the greatest inefficiencies in our society. And you, as a Python freelancer, can eliminate it. This will make your life easier, and you have an unfair advantage compared to any other employee. You can spend the time on learning, recreation, or building more side businesses. You don’t even need a car (I don’t have one), which will save you hundreds of thousands of dollars throughout your lifetime (the average German employee spends 300,000 € for cars).
Family time: During the last 12 months of being self-employed with Python, I watched my 1-year old son walking his first steps and speaking his first words. Many fathers who work at big companies as employees may have missed their sons and daughters growing up. In my environment, most fathers do not have time to spend with their kids during their working days. But I have, and I’m very grateful for this.
Are you already convinced that becoming a Python freelancer is the way to go for you? You are not alone. To help you with your quest, I have created the only Python freelancer course on the web, which pushes you to Python freelancer level in a few months — starting as a beginner coder. The course is designed to pay for itself because it will instantly increase your hourly rate on diverse freelancing platforms such as Upwork or Freelancer.com.
The Bad Things
But it’s not all fun and easy being a Python freelancer. There are a few severe disadvantages which you have to consider before starting your own freelancing business. Let’s dive right into them!
No stability: It’s hard to reach a stable income as a Python freelancer. If you feel only safe if you know exactly how much income you bring home every month, you’ll be terrified as a Python freelancer. Especially if you live from paycheck to paycheck and don’t have yet developed the valuable habit of saving money every month. In this case, being a Python freelancer can be very dangerous because it will ultimately push you out of business within a few bad months. You need to buffer the lack of stability with means of a rigorous savings plan. There is no way around that.
Bad clients: Yes, they exist. If you commit to becoming a Python freelancer, you will get those bad clients for sure. They expect a lot, are never satisfied, give you a bad rating, and don’t even pay you. You might as well already accept this fact and write 10% of your income off as insurance for freeing yourself from any of those bad clients. I’m not kidding — set apart a fraction of your income so that you can always fire the bad clients immediately. You save yourself a lot of time, energy, and ultimately money (time is money in the freelancing business).
Procrastination: Are you a procrastinator? It may be difficult for you to start a freelancing business because this requires that you stay disciplined. No boss kicks your ass if you don’t perform. All initiative is on you. Of course, if you have established a thriving freelancing business, new clients will line up to do business with you. In this case, it may be easier to overcome procrastination. But especially in the early days where you have to make a name for yourself, you must show the discipline which this job profile requires. Make a clear plan for how you acquire clients. For example, if you are a Python freelancer at Upwork, make it a habit to apply for ten projects every day. Yes, you’ve heard this right. Commit first, figure out later. You can always hire your freelancers to help you with this if you have more projects than you can handle. Or even withdraw your services. But doing this will ensure that you never run out of clients, which will practically guarantee your success as a freelancer in the long run.
Legacy code: Kenneth, an experienced Python freelancer, describes this disadvantage as follows: “Python has been around for 25+ years, so, needless to say, there are some projects that have a lot of really old code that might not be up to modern standards. Legacy code presents its own fun challenge. You can’t usually refactor it, at least not easily, because other, equally old, code depends on it. That means you get to remember that this one class with a lowercase name and camel-case methods acts in its own special way. This is another place where you thank your lucky stars if there are docs and tests. Or write to them as quickly as possible if there’s not!” [1]
Competition: Python is a very well documented language. Although the code projects in Python are snowballing, so is the international competition. Many coders are attracted to Python because of its excellent documentation and suitability for machine learning and data science. Thus, the significant advantage of writing Python code that is fun, can sometimes also be the biggest curse. Competition can be fierce. However, this is usually only a problem if you are just starting and have not yet made a name for yourself. If you are doing good work, and focus on one sought-after area (e.g., machine learning nowadays), you have good chances to have plenty of clients competing for your valued time!
Solitude: If you are working as an employee at a company, you always have company, quite literally. You will meet your buddies at the coffee corner, you’ll attend seminars and conferences, you’ll present your work to your group, and you’ll generally get a lot of external input regarding upcoming trends and technology. As a freelancer, you cannot count on these advantages. You have to structure your day well, read books, attend conferences, and meet new people. Otherwise, you will quickly fall out of shape with both your coding and communication skills because you regularly work on your own. The ambitious way out is to continually grow your freelancing business by hiring more and more employees.
What’s unique in Python freelancing compared to general IT or coding freelancing?
Python is a unique language in many ways. The code is clean; there are strict rules (PEP standards), and “writing Pythonic code” is a globally accepted norm of expressing yourself in code. This has the big advantage that usually, you will work on clean and standardized code projects which are easily understandable. This is in stark contrast to languages such as C, where it’s hard to find common ground from time to time.
The Python ecosystem is also incredibly active and vivid — you’ll find tons of resources about every single aspect. As mentioned previously, the documentation is excellent. Many languages such as COBOL (wtf, I know), Go, Haskell and C# are documented poorly in comparison to Python. This helps you a lot when trying to figure out the nasty bugs in your code (or your clients’).
The barrier of entry is also low, which is partly a result of the great documentation, and partly a result of the easy to understand language design. Python is clean and concise — no doubt about that.
Finally, if you plan to start your career in the area of machine learning or data science, Python is the 800-pound gorilla in the room. The library support is stunning — more and more people migrating from Matlab or R to Python because of its generality and the rise of new machine learning frameworks such as TensorFlow.
Knowing about those, let’s dive into the more worldly benefits of becoming a freelance developer.
What’s the Hourly Rate of a Python Freelancer?
Today, many Python freelance developers earn six figures.
How much can you expect to earn as a Python freelancer?
The short answer is: the average Python developer makes between $51 and $61 per hour (worldwide).
This data is based on various sources:
Codementor argues that the average freelancer earns between $61 and $80 in 2019: source
This Subreddit gives a few insights about what some random freelancers earn per hour (it’s usually more than $30 per hour): source
Ziprecruiter finds that the average Python freelancer earns $52 per hour in the US—the equivalent of $8,980 per month or $107,000 per year: source
Payscale is more pessimistic and estimates the average hourly rate around $29 per hour: source
As a Python developer, you can expect to earn between $10 and $80 per hour, with an average salary of $51 (source). I know the variation of the earning potential is high, but so is the quality of the Python freelancers in the wild. Take the average salary as a starting point and add +/- 50% to account for your expertise.
If you work on the side, let’s make it 8 hours each Saturday, you will earn $400 extra per week – or $1600 per month (before taxes). Your hourly rate will be a bit lower because you have to invest time finding freelancing clients – up to 20% of your total time. (source)
1.1 Million USD — How Much You Are Worth as an Average Python Coder?
What’s your market value as a Python developer?
I base this calculation on a standard way of evaluating businesses. In a way, you’re a one-person business when selling your coding skills to the marketplace (whether you’re an employee or a freelancer). When estimating the value of a company, analysts often use multiples of its yearly earnings. Let’s take this approach to come up with a rough estimate of how much your Python skills are worth.
Say, we are taking a low multiple of 10x of your (potential) yearly earning of a Python freelancer.
As an AVERAGE Python freelancer, you’ll earn about $60 per hour.
So the market value of being an average Python coder is:
Yearly Earnings: $60 / hour x 40 hours/week x 46 weeks/year = $110,000 / year
Market Value: Yearly Earnings x 10 = $1.1 Million
As it turns out, Python is a Million-Dollar Skill (even for an average coder)!
And the value of a top 5% coder can easily be 10x or 100x of the average coder:
“A great lathe operator commands several times the wage of an average lathe operator, but a great writer of software code is worth 10,000 times the price of an average software writer.”
Bill Gates
So if you want to thrive with your own coding business, you need to think strategically.
Being cheap costs you hundreds of thousands of dollars. You simply cannot invest too much time, energy, and even money in the right learning material.
Here’s another quote from a billionaire:
“Ultimately, there’s one investment that supersedes all others: Invest in yourself. Nobody can take away what you’ve got in yourself, and everybody has potential they haven’t used yet.”
Warren Buffet
Do you want to know how to go from beginner to average Python freelancer — and even move beyond average?
Then join my Python freelancer program. It’s the world’s most in-depth Python freelancer program — distilling thousands of hours of real-market experience of professional Python freelancers in various industries.
I guarantee that you will earn your first dollars on a freelancer platform within weeks — otherwise, you’ll get your money back.
But one warning: the Python freelancer program is only for those who commit now to invest 1-2 hours every day into their new coding business online. It’s not for the weak players who would rather watch 3.5 hours of Netflix in the evening.
If you fully commit, joining this new venture will be one of the most profitable investments in your life.
Code From Home! How to Be Happier & Earn More Money
What is the number one reason why you should consider working from home?
The number one reason is commute time. It’s healthy and makes you happier to skip commute time altogether.
Commute time is a huge productivity killer and drains your energy. Even if you use the time productively by listening to audiobooks or reading — it’s still a waste of your time.
When I became self-employed, my work productivity skyrocketed. At the same time, work became easier and less stressful. When I analyzed my days to find out about the reason for this, it struck me: No commute time.
Suddenly, I had a lot more time and more energy to create more content. Skipping commute time simply gave me more resources.
Working from home means that you don’t have these enormous drains of energy every day — even more so if you’re involved in a lot of office politics costs.
Many scientific research studies show that having a long commute time makes you less happy. It’s one of the top ten influential factors for your happiness — even more important than making a lot of money with your job.
Working from home is one of the best advantages of being a Python freelancer.
You save 1-2h per day commute time. Invest this commute time into your dream project every day, and you’ll be wildly successful in a few years.
You could write 2-3 books per year, finish ten small web projects per year, or learn and master an entirely new skill such as business or marketing.
What Does it Take to Be a Freelancer?
Surprisingly, many people fear to take the first steps towards freelance development. They are hesitant because they believe that they don’t have enough knowledge, skill, or expertise.
But this is far from the truth. If anything else, it’s a limiting belief that harms their ability to make progress towards their dream life.
The only thing it takes for sure to become a freelancer is to be human (and this may not even be a requirement in the decades to come). Everything else you already have in more — or less — rudimentary form:
Communication skills. You need to ask and respond to questions, figure out what your clients want, be responsive, positive, enthusiastic, and helpful.
Technical skills. There’s always an underlying set of technical skills for which clients hire you. They may want you to develop their next website, write their copy and ads, create valuable content, or solve any other problem. Before being able to deliver the solution, you first need to have the technical skills required to develop this solution.
The ability and ambition to learn. You won’t know everything you need to know to solve the client’s problems. So you need to learn. There’s no way around. If you are willing to learn, you can solve any problem — it’s just a matter of time. And each time you learn more in your area of expertise, the next freelancer gig will become a little bit easier.
Time. All of us have the same number of hours every day. You already have enough time to become a freelancer. You just need to focus your effort—and maybe even skip the Netflix episode this evening.
You see, there’s nothing special about what you need to have to become a freelancer. You already have everything you need to get started. Now, it’s just a matter of your persistence.
Are You Good Enough to Start Earning Money?
André, one of my early students at my “Coffee Break Python” email series, asked me the following question:
“How much do I have to learn to become a Python freelancer?”
My answer is straightforward: start right away — no matter your current skill level.
But I know that for many new Python coders, it’s tough to start right away. Why? Because they don’t have the confidence, yet, to start taking on projects.
And the reason is that they never have quite finished a Python project — and, of course, they are full of doubts and low self-esteem. They fear not being able to finish through with the freelancer project and earn the criticism of their clients.
If you have to overcome this fear first, then I would recommend that you start doing some archived freelancer projects. I always recommend a great resource where you can find these archived freelancer projects (at Freelancer.com). On this resource, you’ll find not only a few but all the freelancer projects in different areas — such as Python, data science, and machine learning — that have ever been published at the Freelancer.com platform. There are thousands of such projects.
Unfortunately, many projects published there are crappy, and it’ll take a lot of time finding suitable projects. To relieve you from this burden, I have compiled a list of 10 suitable Python projects (and published a blog article about that), which you can start doing today to improve your skill level and gain some confidence. Real freelancers have earned real money solving these projects — so they are as practical as they can be.
I recommend that you invest 70% of your learning time finishing these projects. First, you select the project. Second, you finish this project. No matter your current skill level. Even if you are a complete beginner, then it will just take you weeks to finish the project, which earned the freelancer 20 dollars. So what? Then you have worked weeks to make $20 (which you would have invested for learning anyways), and you have improved your skill level a lot. But now you know you can solve the freelancer project.
The next projects will be much easier then. This time, it’ll take you not weeks but a week to finish a similar project. And the next project will take you only three days. And this is how your hourly rate increases exponentially in the beginning until you reach some convergence, and your hourly rate flattens out. At this point, you must specialize even further. Select the skills that interest you and focus on those skills first. Always play your strengths.
Start early
If you want to know how much you can earn and get the overall picture of the state of Python freelancing in 2019, then check out my free webinar: How to earn $3000/M as a Python freelancer. It’ll take you only 30-40 minutes, and I’ll explain to you in detail the state of the art in freelancing, future outlooks and hot skills, and how much you can earn compared to employees and other professions.
Can I Start Freelancing as an Intermediate-Level Python Programmer?
For sure! You should have started much earlier. Have a look at the income distribution of Python freelancers:
It resembles a Gaussian distribution around the average value of $51 per hour. So if you are an average Python freelancer, you can earn $51 per hour in the US!
I have gained a lot of experience at the freelancing platform Upwork.com. Many beginner-level Python coders earn great money finishing smaller code projects. If you are an intermediate-level Python coder and interested in freelancing, you should start earning money ASAP.
The significant benefit is not only that you are getting paid to learn and improving your Python skills even further. It’s also about learning the right skill sets that will make you successful online: communication, marketing, and also coding (the essential practical stuff).
Only practice can push you to the next level. And working as a Python freelancer online will give you a lot of practice for sure!
Are You too Old to Become a Python Freelancer?
The short answer is no. You are not too old.
The older you are, the better your communication skills tend to be. Having excellent communication skills is the main factor for your success in the Python freelancing space.
Just to make this point crystal clear: there are plenty of successful freelancers with limited technical skills that earn even more than highly-skilled employees. They are successful because they are responsive, positive, upbeat, and are committed making the lives of their clients easier. That’s what matters most as a freelancer.
As you see there’s no age barrier here—just double down on your advantages rather than focus too much on your disadvantages.
Are You too Young to Become a Python Freelancer?
The short answer is no. You are not too young.
Was Warren Buffet too young when buying his first stocks at the age of 11? Was Magnus Carlsen, the world’s best chess player, too young when he started playing chess at age 5? Was Mark Zuckerberg too young when he started Facebook?
If anything else, a young age is an advantage, and you should use this advantage by relentlessly pursuing maximal value for your clients. If you do just that, you have a good chance to build yourself a thriving business within a few years.
If you are young, you learn quickly. By focusing your learning on highly practical tasks such as solving problems for clients by using Python code, you create a well-rounded personality and skillset.
Just to make this point crystal clear: there are plenty of successful freelancers earning more than employees who have very limited technical skills. They are successful because they are responsive, positive, upbeat, and are committed making the lives of their clients easier. That’s what matters most as a freelancer.
As you see, there’s no age barrier here—just double down on your advantages rather than focus too much on your disadvantages.
Where to Go From Here
If you want to become a Python freelance developer (and create your coding business online), check out my free webinar “How to Build Your High-Income Skill Python”. Just click the link, register, and watch the webinar immediately. It’s a replay so you won’t have to wait even a minute to watch it. The webinar is an in-depth PowerPoint presentation that will give you a detailed overview of the Python freelancing space.
Today we released a new preview update for Blazor WebAssembly with a bunch of great new features and improvements.
Here’s what’s new in this release:
Version updated to 3.2
Simplified startup
Download size improvements
Support for .NET SignalR client
Get started
To get started with Blazor WebAssembly 3.2.0 Preview 1 install the .NET Core 3.1 SDK and then run the following command:
dotnet new -i Microsoft.AspNetCore.Blazor.Templates::3.2.0-preview1.20073.1
That’s it! You can find additional docs and samples on https://blazor.net.
Upgrade an existing project
To upgrade an existing Blazor WebAssembly app from 3.1.0 Preview 4 to 3.2.0 Preview 1:
Update all Microsoft.AspNetCore.Blazor.* package references to 3.2.0-preview1.20073.1.
In Program.cs in the Blazor WebAssembly client project replace BlazorWebAssemblyHost.CreateDefaultBuilder() with WebAssemblyHostBuilder.CreateDefault().
Move the root component registrations in the Blazor WebAssembly client project from Startup.Configure to Program.cs by calling builder.RootComponents.Add<TComponent>(string selector).
Move the configured services in the Blazor WebAssembly client project from Startup.ConfigureServices to Program.cs by adding services to the builder.Services collection.
Remove Startup.cs from the Blazor WebAssembly client project.
If you’re hosting Blazor WebAssembly with ASP.NET Core, in your Server project replace the call to app.UseClientSideBlazorFiles<Client.Startup>(...) with app.UseClientSideBlazorFiles<Client.Program>(...).
Version updated to 3.2
In this release we updated the versions of the Blazor WebAssembly packages to 3.2 to distinguish them from the recent .NET Core 3.1 Long Term Support (LTS) release. There is no corresponding .NET Core 3.2 release – the new 3.2 version applies only to Blazor WebAssembly. Blazor WebAssembly is currently based on .NET Core 3.1, but it doesn’t inherit the .NET Core 3.1 LTS status. Instead, the initial release of Blazor WebAssembly scheduled for May of this year will be a Current release, which “are supported for three months after a subsequent Current or LTS release” as described in the .NET Core support policy. The next planned release for Blazor WebAssembly after the 3.2 release in May will be with .NET 5. This means that once .NET 5 ships you’ll need to update your Blazor WebAssembly apps to .NET 5 to stay in support.
Simplified startup
We’ve simplified the startup and hosting APIs for Blazor WebAssembly in this release. Originally the startup and hosting APIs for Blazor WebAssembly were designed to mirror the patterns used by ASP.NET Core, but not all of the concepts were relevant. The updated APIs also enable some new scenarios.
Here’s what the new startup code in Program.cs looks like:
public class Program
{ public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add<App>("app"); await builder.Build().RunAsync(); }
}
Blazor WebAssembly apps now support async Main methods for the app entry point.
To a create a default host builder, call WebAssemblyHostBuilder.CreateDefault(). Root components and services are configured using the builder; a separate Startup class is no longer needed.
The following example adds a WeatherService so it’s available through dependency injection (DI):
public class Program
{ public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.Services.AddSingleton<WeatherService>(); builder.RootComponents.Add<App>("app"); await builder.Build().RunAsync(); }
}
Once the host is built, you can access services from the root DI scope before any components have been rendered. This can be useful if you need to run some initialization logic before anything is rendered:
public class Program
{ public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.Services.AddSingleton<WeatherService>(); builder.RootComponents.Add<App>("app"); var host = builder.Build(); var weatherService = host.Services.GetRequiredService<WeatherService>(); await weatherService.InitializeWeatherAsync(); await host.RunAsync(); }
}
The host also now provides a central configuration instance for the app. The configuration isn’t populated with any data by default, but you can populate it as required in your app.
public class Program
{ public static async Task Main(string[] args) { var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.Services.AddSingleton<WeatherService>(); builder.RootComponents.Add<App>("app"); var host = builder.Build(); var weatherService = host.Services.GetRequiredService<WeatherService>(); await weatherService.InitializeWeatherAsync(host.Configuration["WeatherServiceUrl"]); await host.RunAsync(); }
}
Download size improvements
Blazor WebAssembly apps run the .NET IL linker on every build to trim unused code from the app. In previous releases only the core framework libraries were trimmed. Starting with this release the Blazor framework assemblies are trimmed as well resulting in a modest size reduction of about 100 KB transferred. As before, if you ever need to turn off linking, add the <BlazorLinkOnBuild>false</BlazorLinkOnBuild> property to your project file.
Support for the .NET SignalR client
You can now use SignalR from your Blazor WebAssembly apps using the .NET SignalR client.
To give SignalR a try from your Blazor WebAssembly app:
Create an ASP.NET Core hosted Blazor WebAssembly app.
dotnet new blazorwasm -ho -o BlazorSignalRApp
Add the ASP.NET Core SignalR Client package to the Client project.
cd BlazorSignalRApp
dotnet add Client package Microsoft.AspNetCore.SignalR.Client
In the Server project, add the following Hub/ChatHub.cs class.
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR; namespace BlazorSignalRApp.Server.Hubs
{ public class ChatHub : Hub { public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } }
}
In the Server project, add the SignalR services in the Startup.ConfigureServices method.
services.AddSignalR();
Also add an endpoint for the ChatHub in Startup.Configure.
Open the app in two separate browser tabs to chat in real time over SignalR.
Known issues
Below is the list of known issues with this release that will get addressed in a future update.
Running a new ASP.NET Core hosted Blazor WebAssembly app from the command-line results in the warning: CSC : warning CS8034: Unable to load Analyzer assembly C:\Users\user\.nuget\packages\microsoft.aspnetcore.components.analyzers\3.1.0\analyzers\dotnet\cs\Microsoft.AspNetCore.Components.Analyzers.dll : Assembly with same name is already loaded.
Workaround: This warning can be ignored or suppressed using the <DisableImplicitComponentsAnalyzers>true</DisableImplicitComponentsAnalyzers> MSBuild property.
Feedback
We hope you enjoy the new features in this preview release of Blazor WebAssembly! Please let us know what you think by filing issues on GitHub.
I’m excited to announce experimental support for gRPC-Web with .NET. gRPC-Web allows gRPC to be called from browser-based apps like JavaScript SPAs or Blazor WebAssembly apps.
gRPC-Web for .NET promises to bring many of gRPC’s great features to browser apps:
Strongly-typed code-generated clients
Compact Protobuf messages
Server streaming
What is gRPC-Web
It is impossible to implement the gRPC HTTP/2 spec in the browser because there is no browser API with enough fine-grained control over HTTP requests. gRPC-Web solves this problem by being compatible with HTTP/1.1 and HTTP/2.
gRPC-Web is not a new technology. There is a stable gRPC-Web JavaScript client, and a proxy for translating between gRPC and gRPC-Web for services. The new experimental packages allow an ASP.NET Core gRPC app to support gRPC-Web without a proxy, and allow the .NET Core gRPC client to call gRPC-Web services. (great for Blazor WebAssembly apps!)
New opportunites with gRPC-Web
Call ASP.NET Core gRPC apps from the browser – Browser APIs can’t call gRPC HTTP/2. gRPC-Web offers a compatible alternative.
JavaScript SPAs
.NET Blazor Web Assembly apps
Host ASP.NET Core gRPC apps in IIS and Azure App Service – Some servers, such as IIS and Azure App Service, currently can’t host gRPC services. While this is actively being worked on, gRPC-Web offers an interesting alternative that works in every environment today.
Call gRPC from non-.NET Core platforms – Some .NET platforms HttpClient doesn’t support HTTP/2. gRPC-Web can be used to call gRPC services on these platforms (e.g. Blazor WebAssembly, Xamarin).
Note that there is a small performance cost to gRPC-Web, and two gRPC features are no longer supported: client streaming and bi-directional streaming. (server streaming is still supported!)
gRPC-Web does not require any changes to your services, the only modification is startup configuration. To enable gRPC-Web with an ASP.NET Core gRPC service, add a reference to the Grpc.AspNetCore.Web package. Configure the app to use gRPC-Web by adding AddGrpcWeb(...) and UseGrpcWeb() in the startup file:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{ services.AddGrpc();
} public void Configure(IApplicationBuilder app)
{ app.UseRouting(); // Add gRPC-Web middleware after routing and before endpoints app.UseGrpcWeb(); app.UseEndpoints(endpoints => { endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb(); });
}
Some additional configuration may be required to call gRPC-Web from the browser, such as configuring the app to support CORS.
Client gRPC-Web instructions
The JavaScript gRPC-Web client has instructions for setting up a gRPC-Web client to use in browser JavaScript SPAs.
Calling gRPC-Web with a .NET client is the same as regular gRPC, the only modification is how the channel is created. To enable gRPC-Web, add a reference to the Grpc.Net.Client.Web package. Configure the channel to use the GrpcWebHandler:
// Configure a channel to use gRPC-Web
var handler = new GrpcWebHandler(GrpcWebMode.GrpcWebText, new HttpClientHandler());
var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions { HttpClient = new HttpClient(handler) }); var client = Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(new GreeterRequest { Name = ".NET" });
To see gRPC-Web with .NET in action, take a moment to read a great blog post written by Steve Sanderson that uses gRPC-Web in Blazor WebAssembly.
Try gRPC-Web with ASP.NET Core today
Preview packages are on NuGet:
Documentation for using gRPC-Web with .NET Core can be found here.
gRPC-Web for .NET is an experimental project, not a committed product. We want to test that our approach to implementing gRPC-Web works, and get feedback on whether this approach is useful to .NET developers compared to the traditional way of setting up gRPC-Web via a proxy. Please add your feedback here or at the https://github.com/grpc/grpc-dotnet to ensure we build something that developers like and are productive with.
You’re about to learn one of the most frequently used regex operators: the dot regex . in Python’s re library.
What’s the Dot Regex in Python’s Re Library?
The dot regex . matches all characters except the newline character. For example, the regular expression ‘…’ matches strings ‘hey’ and ‘tom’. But it does not match the string ‘yo\ntom’ which contains the newline character ‘\n’.
Let’s study some basic examples to help you gain a deeper understanding.
>>> import re
>>> >>> text = '''But then I saw no harm, and then I heard
Each syllable that breath made up between them.'''
>>> re.findall('B..', text)
['But']
>>> re.findall('heard.Each', text)
[]
>>> re.findall('heard\nEach', text)
['heard\nEach']
>>>
You first import Python’s re library for regular expression handling. Then, you create a multi-line text using the triple string quotes.
Let’s dive into the first example:
>>> re.findall('B..', text)
['But']
You use the re.findall() method. Here’s the definition from the Finxter blog article:
The re.findall(pattern, string) method finds all occurrences of the pattern in the string and returns a list of all matching substrings.
The first argument is the regular expression pattern ‘B..’. The second argument is the string to be searched for the pattern. You want to find all patterns starting with the ‘B’ character, followed by two arbitrary characters except the newline character.
The findall() method finds only one such occurrence: the string ‘But’.
The second example shows that the dot operator does not match the newline character:
>>> re.findall('heard.Each', text)
[]
In this example, you’re looking at the simple pattern ‘heard.Each’. You want to find all occurrences of string ‘heard’ followed by an arbitrary non-whitespace character, followed by the string ‘Each’.
But such a pattern does not exist! Many coders intuitively read the dot regex as an arbitrary character. You must be aware that the correct definition of the dot regex is an arbitrary character except the newline. This is a source of many bugs in regular expressions.
The third example shows you how to explicitly match the newline character ‘\n’ instead:
Naturally, the following relevant question arises:
How to Match an Arbitrary Character (Including Newline)?
The dot regex . matches a single arbitrary character—except the newline character. But what if you do want to match the newline character, too? There are two main ways to accomplish this.
You create a multi-line string. Then you try to find the regex pattern ‘o.p’ in the string. But there’s no match because the dot operator does not match the newline character per default. However, if you define the flag re.DOTALL, the newline character will also be a valid match.
An alternative is to use the slightly more complicated regex pattern [.\n]. The square brackets enclose a character class—a set of characters that are all a valid match. Think of a character class as an OR operation: exactly one character must match.
What If You Actually Want to Match a Dot?
If you use the character ‘.’ in a regular expression, Python assumes that it’s the dot operator you’re talking about. But what if you actually want to match a dot—for example to match the period at the end of a sentence?
Nothing simpler than that: escape the dot regex by using the backslash: ‘\.’. The backslash nullifies the meaning of the special symbol ‘.’ in the regex. The regex engine now knows that you’re actually looking for the dot character, not an arbitrary character except newline.
Here’s an example:
>>> import re
>>> text = 'Python. Is. Great. Period.'
>>> re.findall('\.', text)
['.', '.', '.', '.']
The findall() method returns all four periods in the sentence as matching substrings for the regex ‘\.’.
In this example, you’ll learn how you can combine it with other regular expressions:
>>> re.findall('\.\s', text)
['. ', '. ', '. ']
Now, you’re looking for a period character followed by an arbitrary whitespace. There are only three such matching substrings in the text.
In the next example, you learn how to combine this with a character class:
>>> re.findall('[st]\.', text)
['s.', 't.']
You want to find either character ‘s’ or character ‘t’ followed by the period character ‘.’. Two substrings match this regex.
Note that skipping the backslash is required. If you forget this, it can lead to strange behavior:
>>> re.findall('[st].', text)
['th', 's.', 't.']
As an arbitrary character is allowed after the character class, the substring ‘th’ also matches the regex.
[Collection] What Are The Different Python Re Quantifiers?
If you want to use (and understand) regular expressions in practice, you’ll need to know the most important quantifiers that can be applied to any regex (including the dot regex)!
So let’s dive into the other regexes:
Quantifier
Description
Example
.
The wild-card (‘dot’) matches any character in a string except the newline character ‘n’.
Regex ‘…’ matches all words with three characters such as ‘abc’, ‘cat’, and ‘dog’.
*
The zero-or-more asterisk matches an arbitrary number of occurrences (including zero occurrences) of the immediately preceding regex.
Regex ‘cat*’ matches the strings ‘ca’, ‘cat’, ‘catt’, ‘cattt’, and ‘catttttttt’.
?
The zero-or-one matches (as the name suggests) either zero or one occurrences of the immediately preceding regex.
Regex ‘cat?’ matches both strings ‘ca’ and ‘cat’ — but not ‘catt’, ‘cattt’, and ‘catttttttt’.
+
The at-least-one matches one or more occurrences of the immediately preceding regex.
Regex ‘cat+’ does not match the string ‘ca’ but matches all strings with at least one trailing character ‘t’ such as ‘cat’, ‘catt’, and ‘cattt’.
^
The start-of-string matches the beginning of a string.
Regex ‘^p’ matches the strings ‘python’ and ‘programming’ but not ‘lisp’ and ‘spying’ where the character ‘p’ does not occur at the start of the string.
$
The end-of-string matches the end of a string.
Regex ‘py$’ would match the strings ‘main.py’ and ‘pypy’ but not the strings ‘python’ and ‘pypi’.
A|B
The OR matches either the regex A or the regex B. Note that the intuition is quite different from the standard interpretation of the or operator that can also satisfy both conditions.
Regex ‘(hello)|(hi)’ matches strings ‘hello world’ and ‘hi python’. It wouldn’t make sense to try to match both of them at the same time.
AB
The AND matches first the regex A and second the regex B, in this sequence.
We’ve already seen it trivially in the regex ‘ca’ that matches first regex ‘c’ and second regex ‘a’.
Note that I gave the above operators some more meaningful names (in bold) so that you can immediately grasp the purpose of each regex. For example, the ‘^’ operator is usually denoted as the ‘caret’ operator. Those names are not descriptive so I came up with more kindergarten-like words such as the “start-of-string” operator.
We’ve already seen many examples but let’s dive into even more!
import re text = ''' Ha! let me see her: out, alas! he's cold: Her blood is settled, and her joints are stiff; Life and these lips have long been separated: Death lies on her like an untimely frost Upon the sweetest flower of all the field. ''' print(re.findall('.a!', text)) '''
Finds all occurrences of an arbitrary character that is
followed by the character sequence 'a!'.
['Ha!'] ''' print(re.findall('is.*and', text)) '''
Finds all occurrences of the word 'is',
followed by an arbitrary number of characters
and the word 'and'.
['is settled, and'] ''' print(re.findall('her:?', text)) '''
Finds all occurrences of the word 'her',
followed by zero or one occurrences of the colon ':'.
['her:', 'her', 'her'] ''' print(re.findall('her:+', text)) '''
Finds all occurrences of the word 'her',
followed by one or more occurrences of the colon ':'.
['her:'] ''' print(re.findall('^Ha.*', text)) '''
Finds all occurrences where the string starts with
the character sequence 'Ha', followed by an arbitrary
number of characters except for the new-line character. Can you figure out why Python doesn't find any?
[] ''' print(re.findall('n$', text)) '''
Finds all occurrences where the new-line character 'n'
occurs at the end of the string.
['n'] ''' print(re.findall('(Life|Death)', text)) '''
Finds all occurrences of either the word 'Life' or the
word 'Death'.
['Life', 'Death'] '''
In these examples, you’ve already seen the special symbol ‘\n’ which denotes the new-line character in Python (and most other languages). There are many special characters, specifically designed for regular expressions.
Related Re Methods
There are five important regular expression methods which you should master:
The re.findall(pattern, string) method returns a list of string matches. Read more in our blog tutorial.
The re.search(pattern, string) method returns a match object of the first match. Read more in our blog tutorial.
The re.match(pattern, string) method returns a match object if the regex matches at the beginning of the string. Read more in our blog tutorial.
The re.fullmatch(pattern, string) method returns a match object if the regex matches the whole string. Read more in our blog tutorial.
The re.compile(pattern) method prepares the regular expression pattern—and returns a regex object which you can use multiple times in your code. Read more in our blog tutorial.
The re.split(pattern, string) method returns a list of strings by matching all occurrences of the pattern in the string and dividing the string along those. Read more in our blog tutorial.
The re.sub(The re.sub(pattern, repl, string, count=0, flags=0) method returns a new string where all occurrences of the pattern in the old string are replaced by repl. Read more in our blog tutorial.
These seven methods are 80% of what you need to know to get started with Python’s regular expression functionality.
Where to Go From Here?
You’ve learned everything you need to know about the dot regex . in this regex tutorial.
Summary: The dot regex . matches all characters except the newline character. For example, the regular expression ‘…’ matches strings ‘hey’ and ‘tom’. But it does not match the string ‘yo\ntom’ which contains the newline character ‘\n’.
Want to earn money while you learn Python? Average Python programmers earn more than $50 per hour. You can certainly become average, can’t you?
Join the free webinar that shows you how to become a thriving coding business owner online!