Posted on Leave a comment

Python Re ? Quantifier

Congratulations, you’re about to learn one of the most frequently used regex operators: the question mark quantifier A?.

In particular, this article is all about the ? quantifier in Python’s re library.

What’s the Python Re ? Quantifier

When applied to regular expression A, Python’s A? quantifier matches either zero or one occurrences of A. The ? quantifier always applies only to the preceding regular expression. For example, the regular expression ‘hey?’ matches both strings ‘he’ and ‘hey’. But it does not match the empty string because the ? quantifier does not apply to the whole regex ‘hey’ but only to the preceding regex ‘y’.

Let’s study two basic examples to help you gain a deeper understanding. Do you get all of them?

>>> import re
>>>
>>> re.findall('aa[cde]?', 'aacde aa aadcde')
['aac', 'aa', 'aad']
>>>
>>> re.findall('aa?', 'accccacccac')
['a', 'a', 'a']
>>>
>>> re.findall('[cd]?[cde]?', 'ccc dd ee')
['cc', 'c', '', 'dd', '', 'e', 'e', '']

Don’t worry if you had problems understanding those examples. You’ll learn about them next. Here’s the first example:

>>> re.findall('aa[cde]?', 'aacde aa aadcde')
['aac', 'aa', 'aad']

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.

Please consult the blog article to learn everything you need to know about this fundamental Python method.

The first argument is the regular expression pattern ‘aa[cde]?’. The second argument is the string to be searched for the pattern. In plain English, you want to find all patterns that start with two ‘a’ characters, followed by one optional character—which can be either ‘c’, ‘d’, or ‘e’.

The findall() method returns three matching substrings:

  • First, string ‘aac’ matches the pattern. After Python consumes the matched substring, the remaining substring is ‘de aa aadcde’.
  • Second, string ‘aa’ matches the pattern. Python consumes it which leads to the remaining substring ‘ aadcde’.
  • Third, string ‘aad’ matches the pattern in the remaining substring. What remains is ‘cde’ which doesn’t contain a matching substring anymore.

The second example is the following:

>>> re.findall('aa?', 'accccacccac')
['a', 'a', 'a']

In this example, you’re looking at the simple pattern ‘aa?’. You want to find all occurrences of character ‘a’ followed by an optional second ‘a’. But be aware that the optional second ‘a’ is not needed for the pattern to match.

Therefore, the regex engine finds three matches: the characters ‘a’.

The third example is the following:

>>> re.findall('[cd]?[cde]?', 'ccc dd ee')
['cc', 'c', '', 'dd', '', 'e', 'e', '']

This regex pattern looks complicated: ‘[cd]?[cde]?’. But is it really?

Let’s break it down step-by-step:

The first part of the regex [cd]? defines a character class [cd] which reads as “match either c or d”. The question mark quantifier indicates that you want to match either one or zero occurrences of this pattern.

The second part of the regex [cde]? defines a character class [cde] which reads as “match either c, d, or e”. Again, the question mark indicates the zero-or-one matching requirement.

As both parts are optional, the empty string matches the regex pattern. However, the Python regex engine attempts as much as possible.

Thus, the regex engine performs the following steps:

  • The first match in the string ‘ccc dd ee’ is ‘cc’. The regex engine consumes the matched substring, so the string ‘c dd ee’ remains.
  • The second match in the remaining string is the character ‘c’. The empty space ‘ ‘ does not match the regex so the second part of the regex [cde] does not match. Because of the question mark quantifier, this is okay for the regex engine. The remaining string is ‘ dd ee’.
  • The third match is the empty string ”. Of course, Python does not attempt to match the same position twice. Thus, it moves on to process the remaining string ‘dd ee’.
  • The fourth match is the string ‘dd’. The remaining string is ‘ ee’.
  • The fifth match is the string ”. The remaining string is ‘ee’.
  • The sixth match is the string ‘e’. The remaining string is ‘e’.
  • The seventh match is the string ‘e’. The remaining string is ”.
  • The eighth match is the string ”. Nothing remains.

This was the most complicated of our examples. Congratulations if you understood it completely!

[Collection] What Are The Different Python Re Quantifiers?

The question mark 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-multiple-times regex (I know it sounds a bit clunky): the preceding regex A is matched an arbitrary number of times.

Here’s an example that shows the difference:

>>> import re
>>> re.findall('ab?', 'abbbbbbb')
['ab']
>>> re.findall('ab*', 'abbbbbbb')
['abbbbbbb']

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

Here’s an example that shows the difference:

>>> import re
>>> re.findall('ab?', 'aaaaaaaa')
['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a']
>>> re.findall('ab+', 'aaaaaaaa')
[]

The regex ‘ab?’ matches the character ‘a’ in the string, followed by character ‘b’ if it exists—but it doesn’t in the code.

The regex ‘ab+’ matches the character ‘a’ in the string, 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:

>>> import re
>>> re.findall('a*', 'aaaaaaa')
['aaaaaaa', '']
>>> re.findall('a+', 'aaaaaaa')
['aaaaaaa']
>>> re.findall('a?', 'aaaaaaa')
['a', 'a', 'a', 'a', 'a', 'a', 'a', '']

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:

>>> import re
>>> re.findall('a*?', 'aaaaaaa')
['', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '']
>>> re.findall('a+?', 'aaaaaaa')
['a', 'a', 'a', 'a', 'a', 'a', 'a']
>>> re.findall('a??', 'aaaaaaa')
['', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '', 'a', '']

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 question mark quantifier ? in this regex tutorial.

Summary: When applied to regular expression A, Python’s A? quantifier matches either zero or one occurrences of A. The ? quantifier always applies only to the preceding regular expression. For example, the regular expression ‘hey?’ matches both strings ‘he’ and ‘hey’. But it does not match the empty string because the ? quantifier does not apply to the whole regex ‘hey’ but only to the preceding regex ‘y’.

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!

[Webinar] Become a Six-Figure Freelance Developer with Python

Join us. It’s fun! 🙂

Posted on Leave a comment

Python Regex Sub

Do you want to replace all occurrences of a pattern in a string? You’re in the right place! This article is all about the re.sub(pattern, string) method of Python’s re library.

Let’s answer the following question:

How Does re.sub() Work in Python?

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.

Here’s a minimal example:

>>> import re
>>> text = 'C++ is the best language. C++ rocks!'
>>> re.sub('C\+\+', 'Python', text) 'Python is the best language. Python rocks!'
>>> 

The text contains two occurrences of the string ‘C++’. You use the re.sub() method to search all of those occurrences. Your goal is to replace all those with the new string ‘Python’ (Python is the best language after all).

Note that you must escape the ‘+’ symbol in ‘C++’ as otherwise it would mean the at-least-one regex.

You can also see that the sub() method replaces all matched patterns in the string—not only the first one.

But there’s more! Let’s have a look at the formal definition of the sub() method.

Specification

re.sub(pattern, repl, string, count=0, flags=0)

The method has four arguments—two of which are optional.

  • pattern: the regular expression pattern to search for strings you want to replace.
  • repl: the replacement string or function. If it’s a function, it needs to take one argument (the match object) which is passed for each occurrence of the pattern. The return value of the replacement function is a string that replaces the matching substring.
  • string: the text you want to replace.
  • count (optional argument): the maximum number of replacements you want to perform. Per default, you use count=0 which reads as replace all occurrences of the pattern.
  • flags (optional argument): a more advanced modifier that allows you to customize the behavior of the method. Per default, you don’t use any flags. Want to know how to use those flags? Check out this detailed article on the Finxter blog.

The initial three arguments are required. The remaining two arguments are optional.

You’ll learn about those arguments in more detail later.

Return Value:

A new string where count occurrences of the first substrings that match the pattern are replaced with the string value defined in the repl argument.

Regex Sub Minimal Example

Let’s study some more examples—from simple to more complex.

The easiest use is with only three arguments: the pattern ‘sing’, the replacement string ‘program’, and the string you want to modify (text in our example).

>>> import re
>>> text = 'Learn to sing because singing is fun.'
>>> re.sub('sing', 'program', text) 'Learn to program because programing is fun.'

Just ignore the grammar mistake for now. You get the point: we don’t sing, we program.

But what if you want to actually fix this grammar mistake? After all, it’s programming, not programing. In this case, we need to substitute ‘sing’ with ‘program’ in some cases and ‘sing’ with ‘programm’ in other cases.

You see where this leads us: the sub argument must be a function! So let’s try this:

import re def sub(matched): if matched.group(0)=='singing': return 'programming' else: return 'program' text = 'Learn to sing because singing is fun.'
print(re.sub('sing(ing)?', sub, text))
# Learn to program because programming is fun.

In this example, you first define a substitution function sub. The function takes the matched object as an input and returns a string. If it matches the longer form ‘singing’, it returns ‘programming’. Else it matches the shorter form ‘sing’, so it returns the shorter replacement string ‘program’ instead.

How to Use the count Argument of the Regex Sub Method?

What if you don’t want to substitute all occurrences of a pattern but only a limited number of them? Just use the count argument! Here’s an example:

>>> import re
>>> s = 'xxxxxxhelloxxxxxworld!xxxx'
>>> re.sub('x+', '', s, count=2) 'helloworld!xxxx'
>>> re.sub('x+', '', s, count=3) 'helloworld!'

In the first substitution operation, you replace only two occurrences of the pattern ‘x+’. In the second, you replace all three.

You can also use positional arguments to save some characters:

>>> re.sub('x+', '', s, 3) 'helloworld!'

But as many coders don’t know about the count argument, you probably should use the keyword argument for readability.

How to Use the Optional Flag Argument?

As you’ve seen in the specification, the re.sub() method comes with an optional fourth flag argument:

re.sub(pattern, repl, string, count=0, flags=0)

What’s the purpose of the flags argument?

Flags allow you to control the regular expression engine. Because regular expressions are so powerful, they are a useful way of switching on and off certain features (for example, whether to ignore capitalization when matching your regex).

Syntax Meaning
re.ASCII If you don’t use this flag, the special Python regex symbols w, W, b, B, d, D, s and S will match Unicode characters. If you use this flag, those special symbols will match only ASCII characters — as the name suggests.
re.A Same as re.ASCII
re.DEBUG If you use this flag, Python will print some useful information to the shell that helps you debugging your regex.
re.IGNORECASE If you use this flag, the regex engine will perform case-insensitive matching. So if you’re searching for [A-Z], it will also match [a-z].
re.I Same as re.IGNORECASE
re.LOCALE Don’t use this flag — ever. It’s depreciated—the idea was to perform case-insensitive matching depending on your current locale. But it isn’t reliable.
re.L Same as re.LOCALE
re.MULTILINE This flag switches on the following feature: the start-of-the-string regex ‘^’ matches at the beginning of each line (rather than only at the beginning of the string). The same holds for the end-of-the-string regex ‘$’ that now matches also at the end of each line in a multi-line string.
re.M Same as re.MULTILINE
re.DOTALL Without using this flag, the dot regex ‘.’ matches all characters except the newline character ‘n’. Switch on this flag to really match all characters including the newline character.
re.S Same as re.DOTALL
re.VERBOSE To improve the readability of complicated regular expressions, you may want to allow comments and (multi-line) formatting of the regex itself. This is possible with this flag: all whitespace characters and lines that start with the character ‘#’ are ignored in the regex.
re.X Same as re.VERBOSE

Here’s how you’d use it in a minimal example:

>>> import re
>>> s = 'xxxiiixxXxxxiiixXXX'
>>> re.sub('x+', '', s) 'iiiXiiiXXX'
>>> re.sub('x+', '', s, flags=re.I) 'iiiiii'

In the second substitution operation, you ignore the capitalization by using the flag re.I which is short for re.IGNORECASE. That’s why it substitutes even the uppercase ‘X’ characters that now match the regex ‘x+’, too.

What’s the Difference Between Regex Sub and String Replace?

In a way, the re.sub() method is the more powerful variant of the string.replace() method which is described in detail on this Finxter blog article.

Why? Because you can replace all occurrences of a regex pattern rather than only all occurrences of a string in another string.

So with re.sub() you can do everything you can do with string.replace() but some things more!

Here’s an example:

>>> 'Python is python is PYTHON'.replace('python', 'fun') 'Python is fun is PYTHON'
>>> re.sub('(Python)|(python)|(PYTHON)', 'fun', 'Python is python is PYTHON') 'fun is fun is fun'

The string.replace() method only replaces the lowercase word ‘python’ while the re.sub() method replaces all occurrences of uppercase or lowercase variants.

Note, you can accomplish the same thing even easier with the flags argument.

>>> re.sub('python', 'fun', 'Python is python is PYTHON', flags=re.I) 'fun is fun is fun'

How to Remove Regex Pattern in Python?

Nothing simpler than that. Just use the empty string as a replacement string:

>>> re.sub('p', '', 'Python is python is PYTHON', flags=re.I) 'ython is ython is YTHON'

You replace all occurrences of the pattern 'p' with the empty string ''. In other words, you remove all occurrences of 'p'. As you use the flags=re.I argument, you ignore capitalization.

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.

These five 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 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.

Learning Python is hard. But if you cheat, it isn’t as hard as it has to be:

Download 8 Free Python Cheat Sheets now!

Posted on Leave a comment

Using Kubernetes ConfigMaps to define your Quarkus application’s properties

So, you wrote your Quarkus application, and now you want to deploy it to a Kubernetes cluster. Good news: Deploying a Quarkus application to a Kubernetes cluster is easy. Before you do this, though, you need to straighten out your application’s properties. After all, your app probably has to connect with a database, call other services, and so on. These settings are already defined in your application.properties file, but the values match the ones for your local environment and won’t work once deployed onto your cluster.

So, how do you easily solve this problem? Let’s walk through an example.

Create the example Quarkus application

Instead of using a complex example, let’s take a simple use case that explains the concept well. Start by creating a new Quarkus app:

$ mvn io.quarkus:quarkus-maven-plugin:1.1.1.Final:create

You can keep all of the default values while creating the new application. In this example, the application is named hello-app. Now, open the HelloResource.java file and refactor it to look like this:

@Path("/hello") public class HelloResource { @ConfigProperty(name = "greeting.message") String message; @GET @Produces(MediaType.TEXT_PLAIN) public String hello() { return "hello " + message; } } 

In your application.properties file, now add greeting.message=localhost. The @ConfigProperty annotation is not in the scope of this article, but here we can see how easy it is to inject properties inside our code using this annotation.

Now, let’s start our application to see if it works as expected:

$ mvn compile quarkus:dev

Browse to http://localhost:8080/hello, which should output hello localhost. That’s it for the Quarkus app. It’s ready to go.

Deploy the application to the Kubernetes cluster

The idea here is to deploy this application to our Kubernetes cluster and replace the value of our greeting property with one that will work on the cluster. It is important to know here that all of the properties from application.properties are exposed, and thus can be overridden with environment variables. The convention is to convert the name of the property to uppercase and replace every dot (.) with an underscore (_). So, for instance, our greeting.message will become GREETING_MESSAGE.

At this point, we are almost ready to deploy our app to Kubernetes, but we need to do three more things:

  1. Create a Docker image of your application and push it to a repository that your cluster can access.
  2. Define a ConfgMap resource.
  3. Generate the Kubernetes resources for our application.

To create the Docker image, simply execute this command:

$ docker build -f src/main/docker/Dockerfile.jvm -t quarkus/hello-app .

Be sure to set the right Docker username and to also push to an image registry, like docker-hub or quay. If you are not able to push an image, you can use sebi2706/hello-app:latest.

Next, create the file config-hello.yml:

apiVersion: v1 data: greeting: "Kubernetes" kind: ConfigMap metadata: name: hello-config 

Make sure that you are connected to a cluster and apply this file:

$ kubectl apply -f config-hello.yml

Quarkus comes with a useful extension, quarkus-kubernetes, that generates the Kubernetes resources for you. You can even tweak the generated resources by providing extra properties—for more details, check out this guide.

After installing the extension, add these properties to our application.properties file so it generates extra configuration arguments for our containers specification:

kubernetes.group=yourDockerUsername kubernetes.env-vars[0].name=GREETING_MESSAGE kubernetes.env-vars[0].value=greeting kubernetes.env-vars[0].configmap=hello-config

Run mvn package and view the generated resources in target/kubernetes. The interesting part is in spec.containers.env:

- name: "GREETING_MESSAGE"   valueFrom:   configMapKeyRef:     key: "greeting"    name: "hello-config"

Here, we see how to pass an environment variable to our container with a value coming from a ConfigMap. Now, simply apply the resources:

$ kubectl apply -f target/kubernetes/kubernetes.yml

Expose your service:

kubectl expose deployment hello --type=NodePort

Then, browse to the public URL or do a curl. For instance, with Minikube:

$ curl $(minikube service hello-app --url)/hello

This command should output: hello Kubernetes.

Conclusion

Now you know how to use a ConfigMap in combination with environment variables and your Quarkus’s application.properties. As we said in the introduction, this technique is particularly useful when defining a DB connection’s URL (like QUARKUS_DATASOURCE_URL) or when using the quarkus-rest-client (ORG_SEBI_OTHERSERVICE_MP_REST_URL).

Share

The post Using Kubernetes ConfigMaps to define your Quarkus application’s properties appeared first on Red Hat Developer.

Posted on Leave a comment

Python Regex Split

Why have regular expressions survived seven decades of technological disruption? Because coders who understand regular expressions have a massive advantage when working with textual data. They can write in a single line of code what takes others dozens!

This article is all about the re.split(pattern, string) method of Python’s re library.

Let’s answer the following question:

How Does re.split() Work in Python?

The re.split(pattern, string, maxsplit=0, flags=0) method returns a list of strings by matching all occurrences of the pattern in the string and dividing the string along those.

Here’s a minimal example:

>>> import re
>>> string = 'Learn Python with\t Finxter!'
>>> re.split('\s+', string)
['Learn', 'Python', 'with', 'Finxter!']

The string contains four words that are separated by whitespace characters (in particular: the empty space ‘ ‘ and the tabular character ‘\t’). You use the regular expression ‘\s+’ to match all occurrences of a positive number of subsequent whitespaces. The matched substrings serve as delimiters. The result is the string divided along those delimiters.

But that’s not all! Let’s have a look at the formal definition of the split method.

Specification

re.split(pattern, string, maxsplit=0, flags=0)

The method has four arguments—two of which are optional.

  • pattern: the regular expression pattern you want to use as a delimiter.
  • string: the text you want to break up into a list of strings.
  • maxsplit (optional argument): the maximum number of split operations (= the size of the returned list). Per default, the maxsplit argument is 0, which means that it’s ignored.
  • flags (optional argument): a more advanced modifier that allows you to customize the behavior of the function. Per default the regex module does not consider any flags. Want to know how to use those flags? Check out this detailed article on the Finxter blog.

The first and second arguments are required. The third and fourth arguments are optional.

You’ll learn about those arguments in more detail later.

Return Value:

The regex split method returns a list of substrings obtained by using the regex as a delimiter.

Regex Split Minimal Example

Let’s study some more examples—from simple to more complex.

The easiest use is with only two arguments: the delimiter regex and the string to be split.

>>> import re
>>> string = 'fgffffgfgPythonfgisfffawesomefgffg'
>>> re.split('[fg]+', string)
['', 'Python', 'is', 'awesome', '']

You use an arbitrary number of ‘f’ or ‘g’ characters as regular expression delimiters. How do you accomplish this? By combining the character class regex [A] and the one-or-more regex A+ into the following regex: [fg]+. The strings in between are added to the return list.

How to Use the maxsplit Argument?

What if you don’t want to split the whole string but only a limited number of times. Here’s an example:

>>> string = 'a-bird-in-the-hand-is-worth-two-in-the-bush'
>>> re.split('-', string, maxsplit=5)
['a', 'bird', 'in', 'the', 'hand', 'is-worth-two-in-the-bush']
>>> re.split('-', string, maxsplit=2)
['a', 'bird', 'in-the-hand-is-worth-two-in-the-bush']

We use the simple delimiter regex ‘-‘ to divide the string into substrings. In the first method call, we set maxsplit=5 to obtain six list elements. In the second method call, we set maxsplit=3 to obtain three list elements. Can you see the pattern?

You can also use positional arguments to save some characters:

 >>> re.split('-', string, 2)
['a', 'bird', 'in-the-hand-is-worth-two-in-the-bush']

But as many coders don’t know about the maxsplit argument, you probably should use the keyword argument for readability.

How to Use the Optional Flag Argument?

As you’ve seen in the specification, the re.split() method comes with an optional fourth ‘flag’ argument:

re.split(pattern, string, maxsplit=0, flags=0)

What’s the purpose of the flags argument?

Flags allow you to control the regular expression engine. Because regular expressions are so powerful, they are a useful way of switching on and off certain features (for example, whether to ignore capitalization when matching your regex).

Syntax Meaning
re.ASCII If you don’t use this flag, the special Python regex symbols w, W, b, B, d, D, s and S will match Unicode characters. If you use this flag, those special symbols will match only ASCII characters — as the name suggests.
re.A Same as re.ASCII
re.DEBUG If you use this flag, Python will print some useful information to the shell that helps you debugging your regex.
re.IGNORECASE If you use this flag, the regex engine will perform case-insensitive matching. So if you’re searching for [A-Z], it will also match [a-z].
re.I Same as re.IGNORECASE
re.LOCALE Don’t use this flag — ever. It’s depreciated—the idea was to perform case-insensitive matching depending on your current locale. But it isn’t reliable.
re.L Same as re.LOCALE
re.MULTILINE This flag switches on the following feature: the start-of-the-string regex ‘^’ matches at the beginning of each line (rather than only at the beginning of the string). The same holds for the end-of-the-string regex ‘$’ that now matches also at the end of each line in a multi-line string.
re.M Same as re.MULTILINE
re.DOTALL Without using this flag, the dot regex ‘.’ matches all characters except the newline character ‘n’. Switch on this flag to really match all characters including the newline character.
re.S Same as re.DOTALL
re.VERBOSE To improve the readability of complicated regular expressions, you may want to allow comments and (multi-line) formatting of the regex itself. This is possible with this flag: all whitespace characters and lines that start with the character ‘#’ are ignored in the regex.
re.X Same as re.VERBOSE

Here’s how you’d use it in a practical example:

>>> import re
>>> re.split('[xy]+', text, flags=re.I)
['the', 'russians', 'are', 'coming']

Although your regex is lowercase, we ignore the capitalization by using the flag re.I which is short for re.IGNORECASE. If we wouldn’t do it, the result would be quite different:

>>> re.split('[xy]+', text)
['theXXXYYYrussiansXX', 'are', 'Y', 'coming']

As the character class [xy] only contains lowerspace characters ‘x’ and ‘y’, their uppercase variants appear in the returned list rather than being used as delimiters.

What’s the Difference Between re.split() and string.split() Methods in Python?

The method re.split() is much more powerful. The re.split(pattern, string) method can split a string along all occurrences of a matched pattern. The pattern can be arbitrarily complicated. This is in contrast to the string.split(delimiter) method which also splits a string into substrings along the delimiter. However, the delimiter must be a normal string.

An example where the more powerful re.split() method is superior is in splitting a text along any whitespace characters:

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.split('\s+', 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.', ''] '''

The re.split() method divides the string along any positive number of whitespace characters. You couldn’t achieve such a result with string.split(delimiter) because the delimiter must be a constant-sized string.

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.

These five 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 about the re.split(pattern, string) method that divides the string along the matched pattern occurrences and returns a list of substrings.

Learning Python is hard. But if you cheat, it isn’t as hard as it has to be:

Download 8 Free Python Cheat Sheets now!

Posted on Leave a comment

Shipping API Integration in PHP with Australia Post Example

Last modified on January 22nd, 2020 by Vincy.

In an eCommerce website, we use the shipping API to calculate shipping cost. We calculate based on the items added to the shopping cart.

Integrating Shipping API with an eCommerce website will optimize the logistics cost. It takes care of the shipping needs in an effective way.

Shipping API integration helps eCommerce website by charging the right amount for shipping. Imagine when we add a random fixed cost to each checkout. What will happen is that, we will either overcharge the customer or end up in direct loss.

Australia Post Shipping API Integration in PHP

In this article, we will see how to integrate Australia Post shipping API in a PHP application. You can use this code in a shopping cart checkout page to calculate shipping rates.

I have created code to request the Australia Post API to calculate the shipping rates. This rate is for the products on domestic shipping.

What is inside?

  1. What is Shipping API?
  2. Utilities of third-party shipping API
  3. Existing shipping API available
  4. About Australia Post API
  5. About this example
  6. File Structure
  7. Australia Post shipping API integration steps
  8. Web interface to get data to calculate shipping rates
  9. PHP code with Australia Post shipping API request-response handlers
  10. Australia Post shipping API integration output

What is Shipping API?

Shipping API – a digital intermediate as like as other APIs. It resolves eCommerce website shipping needs.

Integratable extern responds to the queries generated by the application.

With the available services and capabilities, it help build the eCommerce website’s shipping needs.

This ready-made solution will smoothen the customer’s buying experience with your online store.

Capabilities of Shipping APIs

For each eCommerce website, the motive to integrate Shipping API differs. This variation depends on the utilities required by the shopping cart. 

In general, the capabilities of Shipping APIs are,

  1. Verifying shipping zone
  2. Multi-carrier support
  3. Tracking the order traces during shipment.

With these capability limit, the Shipping APIs provides ultimate services. And, they are huge in number. For example,

  1. Ensuring the shipping destination and thereby calculate the success probability of the delivery.
  2. Request a quote for the carrier or shipment.
  3. Receiving notification about tracking updates.

The Australia Post shipping API provides services like,

  • Postage assessment calculation
  • Postal code search 
  • SecurePay online payments and more.

Existing shipping API available

Postal carrier APIs like DHL, USPS, Australia Post provides services for the eCommerce website. It offers services like calculating shipping rates, tracking shipped parcel and more.

There are numerous third-party shipping APIs available.  For example Postmen, EasyPost, Shippo and more.

The third-party shipping API has a RESTful interface that connects postal service APIs. It creates a channel to read the API to access its functionalities.

About Australia Post API

Australia Post API suite has the following list APIs. All these APIs help to fulfil the transactional needs of your eCommerce website.

  1. Postage assessment calculator – To get the cost for shipping a document or parcel.
  2. Shipping and tracking – To get service on product dispatch and tracking. 
  3. SecurePay online payments – Payment solutions for an eCommerce website via SecurePay integration.
  4. Delivery choices API – gives the delivery choices to the user to choose location, speed, day, date, time.

For accessing the API, it requires the corresponding API key. As per the Australia Post API access requirements it asks to register with the API  to get the key.

Australia Post provides an interface to explore the APIs. You may generate live API requests via this explorer to see how it works.

About this example

In this example, it uses the Postage assessment calculator API  or PAC of the Australia Post API suite.

This API provides services to calculate the shipping cost. This cost varies based on the parcel weight, dimension, and more parameters.

This API includes various endpoints returning resources data based on the access requests.

I am creating a request for calculating the shipping cost for a domestic parcel. This request needs the corresponding API key. In the next section, we will see how to get the API key for accessing the PAC API.

For this calculation, the API requires the parcel dimension, height, width. And also, it needs the shipping zone’s origin and destination postal codes. These are all common considering any eCommerce website.

I get the parameters from the user via an HTML form and send it with the API request.

This example uses PHP CURL to access the Australia Post Postage assessment calculator API.

File Structure

The below screenshot shows the Australia Post shipping rate calculation example files.

Shipping API AusPost Files Structure

Australia Post shipping API integration steps

The steps to integrate Australia Post in an eCommerce website are,

  1. Choose API from the Australia Post API suite.
  2. Create a new account to get the API key.
  3. Choose the postage service and set the endpoint.
  4. Set the API key as the HTTP header AUTH-KEY.
  5. Generate the PAC API request with the header set in step 4.

How to get the Australia Post PAC API key

There are many APIs provided by the Australia Post in API suite. The first step is to choose the API based on the need of your eCommerce website.

As discussed in the last section, I choose PAC API for calculating the shipping cost.

The PAC API access requirements state that it need the API key. This key is for authenticating the service request generated from the application.

Aus Post PAC API Registration

On submitting valid information, it will send the API key to the registered email address. You can use this API then, to access the PAC API services.

Getting API Key from Auspost

Web interface to enter details to calculate shipping rates

This is the code to show a form to collect the product and shipping details.  

It has the fields to collect the width, height, weight, and length of the parcel. The form will show the units of these parameters to the user.

 Also, it collects the shipping address. This is the shipping destination address. The zip code is a mandatory field among the shipping address fields.

The shipping origin and destination postal codes are mandatory to calculate the rates.

In this example, the postal code of the shipping origin is configurable. You can also move it to the HTML form to let the user enter the data.

index.php

<HTML> <HEAD> <TITLE>Shipping API</TITLE> <link href="./assets/css/phppot-style.css" type="text/css" rel="stylesheet" /> <link href="./assets/css/shipping-api.css" type="text/css" rel="stylesheet" /> <script src="./vendor/jquery/jquery-3.3.1.js" type="text/javascript"></script> </HEAD> <BODY> <div class="phppot-container"> <div class="australian-api"> <div class="page-heading">Australian Shipping API</div> <form name="australian-api" id="australian-api" action="" method="post" onsubmit="return formValidation()"> <div class="sub-heading">Product Details</div> <div class="row"> <div class="inline-block"> <div class="form-label"> Length<span class="units-style">(cm)</span><span class="required error" id="length-info"></span> </div> <input class="input-box-110" type="text" name="length" id="length" value="<?php if(! empty($_POST["length"])){ echo $_POST["length"];}?>"> </div> <div class="inline-block input-right-margin"> <div class="form-label"> Width<span class="units-style">(cm)</span><span class="required error" id="width-info"></span> </div> <input class="input-box-110" type="text" name="width" id="width" value="<?php if(! empty($_POST["width"])){ echo $_POST["width"];}?>"> </div> <div class="inline-block"> <div class="form-label"> Height<span class="units-style">(cm)</span><span class="required error" id="height-info"></span> </div> <input class="input-box-110" type="text" name="height" id="height" value="<?php if(! empty($_POST["height"])){ echo $_POST["height"];}?>"> </div> <div class="inline-block input-right-margin"> <div class="form-label"> Weight<span class="units-style">(kg)</span><span class="required error" id="weight-info"></span> </div> <input class="input-box-110" type="text" name="weight" id="weight" value="<?php if(! empty($_POST["weight"])){ echo $_POST["weight"];}?>"> </div> </div> <div class="row"> <div class="inline-block"> <div class="form-label"> Quantity<span class="required error" id="quantity-info"></span> </div> <input class="input-box-110" type="number" name="quantity" id="quantity" value="<?php if(! empty($_POST["quantity"])){ echo $_POST["quantity"];}else{echo 1;}?>"> </div> </div> <div class="sub-heading">Shipping Address</div> <div class="row"> <div class="inline-block input-right-margin"> <div class="form-label">Address1</div> <input class="input-box-330" type="text" name="address1" id="address1" value="<?php if(! empty($_POST["address1"])){ echo $_POST["address1"];}?>"> </div> <div class="inline-block"> <div class="form-label">Address2</div> <input class="input-box-330" type="text" name="address2" id="address2" value="<?php if(! empty($_POST["address2"])){ echo $_POST["address2"];}?>"> </div> </div> <div class="row"> <div class="inline-block input-right-margin"> <div class="form-label">Country</div> <input class="input-box-330" type="text" name="country" id="country" value="<?php if(! empty($_POST["country"])){ echo $_POST["country"];}?>"> </div> <div class="inline-block"> <div class="form-label">State</div> <input class="input-box-330" type="text" name="state" id="state" value="<?php if(! empty($_POST["state"])){ echo $_POST["state"];}?>"> </div> </div> <div class="row"> <div class="inline-block input-right-margin"> <div class="form-label">City</div> <input class="input-box-330" type="text" name="city" id="city" value="<?php if(! empty($_POST["city"])){ echo $_POST["city"];}?>"> </div> <div class="inline-block"> <div class="form-label"> Zip Code<span class="required error" id="to-postcode-info"></span> </div> <input class="input-box-330" type="text" name="to-postcode" id="to-postcode" value="<?php if(! empty($_POST["to-postcode"])){ echo $_POST["to-postcode"];}?>"> </div> </div> <div class="row"> <div id="inline-block"> <input type="submit" class="submit-button" name="submit-btn" id="submit-btn" value="Get Quote"><span><img src="img/loader.gif" class="loader-ic" id="loader-icon"></span> </div> </div> </form> <?php if (! empty($shippingPrice)) { ?><div> <div class="sub-heading">Shipping Details</div> <div class="row"> <label class="shipping-result">Address1:</label> <?php echo $address1;?></div> <div class="row"> <label class="shipping-result">Address2:</label> <?php echo $address2;?></div> <div class="row"> <label class="shipping-result">Country:</label> <?php echo $country;?></div> <div class="row"> <label class="shipping-result">State:</label> <?php echo $state;?></div> <div class="row"> <label class="shipping-result">City:</label> <?php echo $city;?></div> <div class="row"> <label class="shipping-result">Quantity:</label> <?php echo $quantity;?></div> <div class="row"> <label class="shipping-result">Shipping price:</label> $<?php echo $quantity * $shippingPrice;?></div> </div> <?php }else if(!empty($errorMsg)){?> <div class="error-message"><?php echo $errorMsg;?></div> <?php }?> </div> </div> <script src="./assets/js/shipping.js"></script> </BODY> </HTML> 

CSS created to present the payment form

This CSS includes basic styles to show the shipping form to the user. It has exclusive styles related to this example.

Apart from that, this example contains a generic CSS phppot-styles.css. It contains common template styles with a list of selectors. You can find this generic CSS in the downloadable source.

assets/css/shipping-api.css

.australian-api { background: #fff; border-radius: 4px; padding: 10px; width: 85%; margin: 20px 40px; } .page-heading { font-size: 2em; font-weight: bold; } .sub-heading { font-size: 1.2em; font-weight: bold; margin: 20px 0px; } .inline-block { display: inline-block; } .row { margin: 15px 0px; } .form-label { margin-bottom: 5px; text-align: left; } input.input-box-330 { width: 250px; } input.input-box-110 { width: 120px; margin-right: 5px; } .australian-api .error { color: #ee0000; padding: 0px; background: none; border: #ee0000; } .australian-api .error-field { border: 1px solid #d96557; } .australian-api .error:before { content: '*'; padding: 0 3px; color: #D8000C; } input.submit-button { background-color: #ffb932; border-color: #ffc87a #e2a348 #da9d0a; text-align: center; cursor: pointer; color: #000; width: 100px; } .input-right-margin { margin-right: 30px; } .shipping-result { font-weight: bold; color: #737171; padding: 15px 0px; } .error-message { color: #D8000C; } .units-style { font-size: 0.8em; color: #666; margin-left: 2px; } .loader-ic { display: none; } 

jQuery script to validate the shipping details

The shipping.js file contains the form validation function. It validates the mandatory fields and makes sure that they are not empty.

It returns boolean based on which the form-post carried forward to PHP. While returning false, it highlights what’s wrong with the entered data.

After successful validation, PHP will validate the shipping attributes sent via the form.

assets/js/shipping.js

function formValidation() { var valid = true; $("#length").removeClass("error-field"); $("#width").removeClass("error-field"); $("#height").removeClass("error-field"); $("#weight").removeClass("error-field"); $("#quantity").removeClass("error-field"); $("#to-postcode").removeClass("error-field"); var Length = $("#length").val(); var Width = $("#width").val(); var Height = $("#height").val(); var Weight = $("#weight").val(); var Quantity = $("#quantity").val(); var toPostcode = $("#to-postcode").val(); if (Length.trim() == "") { $("#length-info").html("").css("color", "#ee0000").show(); $("#length").addClass("error-field"); valid = false; } if (Width.trim() == "") { $("#width-info").css("color", "#ee0000").show(); $("#width").addClass("error-field"); valid = false; } if (Height.trim() == "") { $("#height-info").css("color", "#ee0000").show(); $("#height").addClass("error-field"); valid = false; } if (Weight.trim() == "") { $("#weight-info").css("color", "#ee0000").show(); $("#weight").addClass("error-field"); valid = false; } if (Quantity.trim() == "" || Quantity < 1) { $("#quantity-info").css("color", "#ee0000").show(); $("#quantity").addClass("error-field"); valid = false; } if (toPostcode.trim() == "") { $("#to-postcode-info").css("color", "#ee0000").show(); $("#to-postcode").addClass("error-field"); valid = false; } if (valid == false) { $('.error-field').first().focus(); valid = false; } if (valid == true) { $("#submit-btn").hide(); $("#loader-icon").show(); } return valid; } 

PHP code with Australia Post shipping API request-response handlers

This is the configuration file of this example code. It has the constants defined for keeping the API key and shipping origin.

Common/Config.php

<?php namespace Phppot; class Config { const AUSTRALIAN_POST_API_KEY = 'REPLACE_WITH_THE_API_KEY'; const SHIPPING_ORIGION = '1000'; } ?> 

This is an exclusive service class for executing curl script. The execute() function is receiving URL, API KEY as its parameters.

It initiates curl object and set the URL. It sets the header with the API key to call the Australia Post live URL.

The rawBody will receive the API response in JSON format. You can use this as a sample to build an eCommerce website backed by a shopping cart with shipping API integration.

lib/CurlService.php

<?php namespace Phppot; class CurlService { public function execute($url, $apiKey, $ch = null) { if (is_null($ch)) { $ch = curl_init(); } curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'AUTH-KEY: ' . $apiKey )); return $rawBody = curl_exec($ch); } } ?> 

The AusPost.php PHP class handles the operation for preparing the API request.

The getShipmentPrice() function set the API key and form data to the PHP variables. It prepares the query parameters with these variables.

The class constructor instantiates the curlService created for this example.

Using the curl instance, it hits the Australia Post live PAC API URL. The API will validate the shipping criteria passed with the query parameters.

The request and response can be of either JSON or XML.

lib/AusPost.php

<?php namespace Phppot; class AusPost { private $curlService; private $api_url = 'https://digitalapi.auspost.com.au/postage/parcel/domestic/calculate?'; public function __construct() { require_once __DIR__ . '/CurlService.php'; $this->curlService = new CurlService(); } public function getShipmentPrice() { require_once __DIR__ . '/../Common/Config.php'; $con = new Config(); $apiKey = $con::AUSTRALIAN_POST_API_KEY; $fromPostcode = $con::SHIPPING_ORIGION; $toPostcode = $_POST["to-postcode"]; $length = $_POST["length"]; $width = $_POST["width"]; $height = $_POST["height"]; $weight = $_POST["weight"]; $queryParams = array( "from_postcode" => $fromPostcode, "to_postcode" => $toPostcode, "length" => $length, "width" => $width, "height" => $height, "weight" => $weight, "service_code" => "AUS_PARCEL_REGULAR" ); // here use $curlService and execute $url = $this->api_url . http_build_query($queryParams); $result = $this->curlService->execute($url, $apiKey); $shippingResult = json_decode($result); return $shippingResult; } } ?> 

index.php (PHP Code)

<?php namespace Phppot; if (! empty($_POST["submit-btn"])) { require_once __DIR__ . '/lib/AusPost.php'; $shippingApi = new AusPost(); $result = $shippingApi->getShipmentPrice(); if (isset($result->postage_result)) { $shippingPrice = $result->postage_result->total_cost; } else { $errorMsg = $result->error->errorMessage; } $quantity = $_POST["quantity"]; $address1 = $_POST["address1"]; $address2 = $_POST["address2"]; $state = $_POST["state"]; $country = $_POST["country"]; $city = $_POST["city"]; } ?> 

Australia Post shipping API integration output

The output screenshot below shows the payment and shipping form. It is to get the shipping details from the user.

It also has the fields to collect parameters like height, width and the dimension of the products.

You can also integrate this form into your shopping cart checkout page to calculate rates. For a shopping cart, it requires only the shipping address.

Because, the height, width, height will be a part of a product entity. And the quantity can be read from the cart session or database. The below form is generic and with little customization can be used for any eCommerce website.

Shipping API Australia Post User Interface

Download

↑ Back to Top

Posted on Leave a comment

Python Regex Compile

Why have regular expressions survived seven decades of technological disruption? Because coders who understand regular expressions have a massive advantage when working with textual data. They can write in a single line of code what takes others dozens!

This article is all about the re.compile(pattern) method of Python’s re library. Before we dive into re.compile(), let’s get an overview of the four related methods you must understand:

  • The findall(pattern, string) method returns a list of string matches. Read more in our blog tutorial.
  • The search(pattern, string) method returns a match object of the first match. Read more in our blog tutorial.
  • The 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 fullmatch(pattern, string) method returns a match object if the regex matches the whole string. Read more in our blog tutorial.

Equipped with this quick overview of the most critical regex methods, let’s answer the following question:

How Does re.compile() Work in Python?

The re.compile(pattern) method returns a regular expression object (see next section)

You then use the object to call important regex methods such as search(string), match(string), fullmatch(string), and findall(string).

In short: You compile the pattern first. You search the pattern in a string second.

This two-step approach is more efficient than calling, say, search(pattern, string) at once. That is, IF you call the search() method multiple times on the same pattern. Why? Because you can reuse the compiled pattern multiple times.

Here’s an example:

import re # These two lines ...
regex = re.compile('Py...n')
match = regex.search('Python is great') # ... are equivalent to ...
match = re.search('Py...n', 'Python is great')

In both instances, the match variable contains the following match object:

<re.Match object; span=(0, 6), match='Python'>

But in the first case, we can find the pattern not only in the string ‘Python is great’ but also in other strings—without any redundant work of compiling the pattern again and again.

Specification:

re.compile(pattern, flags=0)

The method has up to two arguments.

We’ll explore those arguments in more detail later.

Return Value:

The re.compile(patterns, flags) method returns a regular expression object. You may ask (and rightly so):

What’s a Regular Expression Object?

Python internally creates a regular expression object (from the Pattern class) to prepare the pattern matching process. You can call the following methods on the regex object:

Method Description
Pattern.search(string[, pos[, endpos]]) Searches the regex anywhere in the string and returns a match object or None. You can define start and end positions of the search.
Pattern.match(string[, pos[, endpos]]) Searches the regex at the beginning of the string and returns a match object or None. You can define start and end positions of the search.
Pattern.fullmatch(string[, pos[, endpos]]) Matches the regex with the whole string and returns a match object or None. You can define start and end positions of the search.
Pattern.split(string, maxsplit=0) Divides the string into a list of substrings. The regex is the delimiter. You can define a maximum number of splits.
Pattern.findall(string[, pos[, endpos]]) Searches the regex anywhere in the string and returns a list of matching substrings. You can define start and end positions of the search.
Pattern.finditer(string[, pos[, endpos]]) Returns an iterator that goes over all matches of the regex in the string (returns one match object after another). You can define the start and end positions of the search.
Pattern.sub(repl, string, count=0) Returns a new string by replacing the first count occurrences of the regex in the string (from left to right) with the replacement string repl.
Pattern.subn(repl, string, count=0) Returns a new string by replacing the first count occurrences of the regex in the string (from left to right) with the replacement string repl. However, it returns a tuple with the replaced string as the first and the number of successful replacements as the second tuple value.

If you’re familiar with the most basic regex methods, you’ll realize that all of them appear in this table. But there’s one distinction: you don’t have to define the pattern as an argument. For example, the regex method re.search(pattern, string) will internally compile a regex object p and then call p.search(string).

You can see this fact in the official implementation of the re.search(pattern, string) method:

def search(pattern, string, flags=0): """Scan through string looking for a match to the pattern, returning a Match object, or None if no match was found.""" return _compile(pattern, flags).search(string)

(Source: GitHub repository of the re package)

The re.search(pattern, string) method is a mere wrapper for compiling the pattern first and calling the p.search(string) function on the compiled regex object p.

Is It Worth Using Python’s re.compile()?

No, in the vast majority of cases, it’s not worth the extra line.

Consider the following example:

import re # These two lines ...
regex = re.compile('Py...n')
match = regex.search('Python is great') # ... are equivalent to ...
match = re.search('Py...n', 'Python is great')

Don’t get me wrong. Compiling a pattern once and using it many times throughout your code (e.g., in a loop) comes with a big performance benefit. In some anecdotal cases, compiling the pattern first lead to 10x to 50x speedup compared to compiling it again and again.

But the reason it is not worth the extra line is that Python’s re library ships with an internal cache. At the time of this writing, the cache has a limit of up to 512 compiled regex objects. So for the first 512 times, you can be sure when calling re.search(pattern, string) that the cache contains the compiled pattern already.

Here’s the relevant code snippet from re’s GitHub repository:

# --------------------------------------------------------------------
# internals _cache = {} # ordered! _MAXCACHE = 512
def _compile(pattern, flags): # internal: compile pattern if isinstance(flags, RegexFlag): flags = flags.value try: return _cache[type(pattern), pattern, flags] except KeyError: pass if isinstance(pattern, Pattern): if flags: raise ValueError( "cannot process flags argument with a compiled pattern") return pattern if not sre_compile.isstring(pattern): raise TypeError("first argument must be string or compiled pattern") p = sre_compile.compile(pattern, flags) if not (flags & DEBUG): if len(_cache) >= _MAXCACHE: # Drop the oldest item try: del _cache[next(iter(_cache))] except (StopIteration, RuntimeError, KeyError): pass _cache[type(pattern), pattern, flags] = p return p

Can you find the spots where the cache is initialized and used?

While in most cases, you don’t need to compile a pattern, in some cases, you should. These follow directly from the previous implementation:

  • You’ve got more than MAXCACHE patterns in your code.
  • You’ve got more than MAXCACHE different patterns between two same pattern instances. Only in this case, you will see “cache misses” where the cache has already flushed the seemingly stale pattern instances to make room for newer ones.
  • You reuse the pattern multiple times. Because if you don’t, it won’t make sense to use sparse memory to save them in your memory.
  • (Even then, it may only be useful if the patterns are relatively complicated. Otherwise, you won’t see a lot of performance benefits in practice.)

To summarize, compiling the pattern first and storing the compiled pattern in a variable for later use is often nothing but “premature optimization”—one of the deadly sins of beginner and intermediate programmers.

What Does re.compile() Really Do?

It doesn’t seem like a lot, does it? My intuition was that the real work is in finding the pattern in the text—which happens after compilation. And, of course, matching the pattern is the hard part. But a sensible compilation helps a lot in preparing the pattern to be matched efficiently by the regex engine—work that would otherwise have be done by the regex engine.

Regex’s compile() method does a lot of things such as:

  • Combine two subsequent characters in the regex if they together indicate a special symbol such as certain Greek symbols.
  • Prepare the regex to ignore uppercase and lowercase.
  • Check for certain (smaller) patterns in the regex.
  • Analyze matching groups in the regex enclosed in parentheses.

Here’s the implemenation of the compile() method—it looks more complicated than expected, no?

def _compile(code, pattern, flags): # internal: compile a (sub)pattern emit = code.append _len = len LITERAL_CODES = _LITERAL_CODES REPEATING_CODES = _REPEATING_CODES SUCCESS_CODES = _SUCCESS_CODES ASSERT_CODES = _ASSERT_CODES iscased = None tolower = None fixes = None if flags & SRE_FLAG_IGNORECASE and not flags & SRE_FLAG_LOCALE: if flags & SRE_FLAG_UNICODE: iscased = _sre.unicode_iscased tolower = _sre.unicode_tolower fixes = _ignorecase_fixes else: iscased = _sre.ascii_iscased tolower = _sre.ascii_tolower for op, av in pattern: if op in LITERAL_CODES: if not flags & SRE_FLAG_IGNORECASE: emit(op) emit(av) elif flags & SRE_FLAG_LOCALE: emit(OP_LOCALE_IGNORE[op]) emit(av) elif not iscased(av): emit(op) emit(av) else: lo = tolower(av) if not fixes: # ascii emit(OP_IGNORE[op]) emit(lo) elif lo not in fixes: emit(OP_UNICODE_IGNORE[op]) emit(lo) else: emit(IN_UNI_IGNORE) skip = _len(code); emit(0) if op is NOT_LITERAL: emit(NEGATE) for k in (lo,) + fixes[lo]: emit(LITERAL) emit(k) emit(FAILURE) code[skip] = _len(code) - skip elif op is IN: charset, hascased = _optimize_charset(av, iscased, tolower, fixes) if flags & SRE_FLAG_IGNORECASE and flags & SRE_FLAG_LOCALE: emit(IN_LOC_IGNORE) elif not hascased: emit(IN) elif not fixes: # ascii emit(IN_IGNORE) else: emit(IN_UNI_IGNORE) skip = _len(code); emit(0) _compile_charset(charset, flags, code) code[skip] = _len(code) - skip elif op is ANY: if flags & SRE_FLAG_DOTALL: emit(ANY_ALL) else: emit(ANY) elif op in REPEATING_CODES: if flags & SRE_FLAG_TEMPLATE: raise error("internal: unsupported template operator %r" % (op,)) if _simple(av[2]): if op is MAX_REPEAT: emit(REPEAT_ONE) else: emit(MIN_REPEAT_ONE) skip = _len(code); emit(0) emit(av[0]) emit(av[1]) _compile(code, av[2], flags) emit(SUCCESS) code[skip] = _len(code) - skip else: emit(REPEAT) skip = _len(code); emit(0) emit(av[0]) emit(av[1]) _compile(code, av[2], flags) code[skip] = _len(code) - skip if op is MAX_REPEAT: emit(MAX_UNTIL) else: emit(MIN_UNTIL) elif op is SUBPATTERN: group, add_flags, del_flags, p = av if group: emit(MARK) emit((group-1)*2) # _compile_info(code, p, _combine_flags(flags, add_flags, del_flags)) _compile(code, p, _combine_flags(flags, add_flags, del_flags)) if group: emit(MARK) emit((group-1)*2+1) elif op in SUCCESS_CODES: emit(op) elif op in ASSERT_CODES: emit(op) skip = _len(code); emit(0) if av[0] >= 0: emit(0) # look ahead else: lo, hi = av[1].getwidth() if lo != hi: raise error("look-behind requires fixed-width pattern") emit(lo) # look behind _compile(code, av[1], flags) emit(SUCCESS) code[skip] = _len(code) - skip elif op is CALL: emit(op) skip = _len(code); emit(0) _compile(code, av, flags) emit(SUCCESS) code[skip] = _len(code) - skip elif op is AT: emit(op) if flags & SRE_FLAG_MULTILINE: av = AT_MULTILINE.get(av, av) if flags & SRE_FLAG_LOCALE: av = AT_LOCALE.get(av, av) elif flags & SRE_FLAG_UNICODE: av = AT_UNICODE.get(av, av) emit(av) elif op is BRANCH: emit(op) tail = [] tailappend = tail.append for av in av[1]: skip = _len(code); emit(0) # _compile_info(code, av, flags) _compile(code, av, flags) emit(JUMP) tailappend(_len(code)); emit(0) code[skip] = _len(code) - skip emit(FAILURE) # end of branch for tail in tail: code[tail] = _len(code) - tail elif op is CATEGORY: emit(op) if flags & SRE_FLAG_LOCALE: av = CH_LOCALE[av] elif flags & SRE_FLAG_UNICODE: av = CH_UNICODE[av] emit(av) elif op is GROUPREF: if not flags & SRE_FLAG_IGNORECASE: emit(op) elif flags & SRE_FLAG_LOCALE: emit(GROUPREF_LOC_IGNORE) elif not fixes: # ascii emit(GROUPREF_IGNORE) else: emit(GROUPREF_UNI_IGNORE) emit(av-1) elif op is GROUPREF_EXISTS: emit(op) emit(av[0]-1) skipyes = _len(code); emit(0) _compile(code, av[1], flags) if av[2]: emit(JUMP) skipno = _len(code); emit(0) code[skipyes] = _len(code) - skipyes + 1 _compile(code, av[2], flags) code[skipno] = _len(code) - skipno else: code[skipyes] = _len(code) - skipyes + 1 else: raise error("internal: unsupported operand type %r" % (op,))

Don’t worry, you don’t need to understand the code. Just note that all this work would have to be done by the regex engine at “matching runtime” if you wouldn’t compile the pattern first. If we can do it only once, it’s certainly a low-hanging fruit for performance optimizations—especially for long regular expression patterns.

How to Use the Optional Flag Argument?

As you’ve seen in the specification, the compile() method comes with an optional third ‘flag’ argument:

re.compile(pattern, flags=0)

What’s the purpose of the flags argument?

Flags allow you to control the regular expression engine. Because regular expressions are so powerful, they are a useful way of switching on and off certain features (for example, whether to ignore capitalization when matching your regex).

Syntax Meaning
re.ASCII If you don’t use this flag, the special Python regex symbols w, W, b, B, d, D, s and S will match Unicode characters. If you use this flag, those special symbols will match only ASCII characters — as the name suggests.
re.A Same as re.ASCII
re.DEBUG If you use this flag, Python will print some useful information to the shell that helps you debugging your regex.
re.IGNORECASE If you use this flag, the regex engine will perform case-insensitive matching. So if you’re searching for [A-Z], it will also match [a-z].
re.I Same as re.IGNORECASE
re.LOCALE Don’t use this flag — ever. It’s depreciated—the idea was to perform case-insensitive matching depending on your current locale. But it isn’t reliable.
re.L Same as re.LOCALE
re.MULTILINE This flag switches on the following feature: the start-of-the-string regex ‘^’ matches at the beginning of each line (rather than only at the beginning of the string). The same holds for the end-of-the-string regex ‘$’ that now matches also at the end of each line in a multi-line string.
re.M Same as re.MULTILINE
re.DOTALL Without using this flag, the dot regex ‘.’ matches all characters except the newline character ‘n’. Switch on this flag to really match all characters including the newline character.
re.S Same as re.DOTALL
re.VERBOSE To improve the readability of complicated regular expressions, you may want to allow comments and (multi-line) formatting of the regex itself. This is possible with this flag: all whitespace characters and lines that start with the character ‘#’ are ignored in the regex.
re.X Same as re.VERBOSE

Here’s how you’d use it in a practical example:

import re text = 'Python is great (python really is)' regex = re.compile('Py...n', flags=re.IGNORECASE) matches = regex.findall(text)
print(matches)
# ['Python', 'python']

Although your regex ‘Python’ is uppercase, we ignore the capitalization by using the flag re.IGNORECASE.

Where to Go From Here?

You’ve learned about the re.compile(pattern) method that prepares the regular expression pattern—and returns a regex object which you can use multiple times in your code.

Learning Python is hard. But if you cheat, it isn’t as hard as it has to be:

Download 8 Free Python Cheat Sheets now!

Posted on Leave a comment

JetBrains Mono–A Font For Programmers

JetBrains, the makers of programmer tools such as IntelliJ, WebStorm, CLion and Rider, as well as the programming language Kotlin have been working on a font specifically designed for code.  JetBrains Mono is an open source font family consisting of 8 fonts specifically designed with reading and writing code in mind.

Details from the JetBrains blog:

For the most part of our day we, as developers, look at the code. And it is no wonder that we are always on the lookout for the best font to make looking at the text on the screen easier on our eyes. However, the logic in many popular fonts does not always take into account the difference between reading through code and reading a book. Our eyes move along code in a very different way, often having to move vertically as often as they do horizontally, which is opposed to reading a book where they slide along the text always in the same direction.

Therefore, while working on JetBrains Mono we focused, among other things, on the issues that can cause eye fatigue during long sessions of working with code. We have considered things like the size and shape of letters; the amount of space between them, a balance naturally engineered in monospace fonts; unnecessary details and unclear distinctions between symbols, such as I’s and l’s for example; and programming ligatures when developing our font.

Today, we proudly present JetBrains Mono – a new open-source typeface specifically made for developers. Check out what makes JetBrains Mono unique in the big family of monospaced fonts and try it in your favorite code editor. Have a look at JetBrains Mono, your eyes will thank you for it.

More details about Mono are available here.  It is the default font on all 2020 JetBrains IDEs and is available as an option in version 2019.3 and beyond of all JetBrain products.  If you use another IDE you can download the zip here.  Learn more about JetBrains Mono, including how to install and configure in Visual Studio Code in the video below.

[youtube https://www.youtube.com/watch?v=AyCZ0dVlz4A&w=853&h=480]

Programming GameDev News


<!–

–>

Posted on Leave a comment

Announcing Experimental Mobile Blazor Bindings

Eilon Lipton

Eilon

Today I’m excited to announce a new experimental project to enable native mobile app development with Blazor: Experimental Mobile Blazor Bindings. These bindings enable developers to build native mobile apps using C# and .NET for iOS and Android using familiar web programming patterns. This means you can use the Blazor programming model and Razor syntax to define UI components and behaviors of an application. The UI components that are included are based on Xamarin.Forms native UI controls, which results in beautiful native mobile apps.

Here is a sample Counter component, which may look familiar to Blazor developers, that increments a value on each button press:

<StackLayout> <Label FontSize="30" Text="@("You pressed " + count + " times")" /> <Button Text="+1" OnClick="@HandleClick" />
</StackLayout> @code { int count; void HandleClick() { count++; }
}

Notice that the Blazor model is present with code sitting side by side the user interface markup that leverages Razor syntax with mobile specific components. This will feel very natural for any web developer that has ever used Razor syntax in the past. Now with the Experimental Mobile Blazor Bindings you can leverage your existing web skills and knowledge to build native iOS and Android apps powered by .NET.

Here is the code above running in the Android Emulator:

Clicking increment button in Android emulator

Get started with Mobile Blazor Bindings

To get started, all you need is the .NET Core 3.0 or 3.1 SDK, Visual Studio or Visual Studio for Mac, and the ASP.NET and web development and Mobile development with .NET (Xamarin.Forms) workloads installed.

Install the templates by running this command from a command/shell window:

dotnet new -i Microsoft.MobileBlazorBindings.Templates::0.1.173-beta

And then create your first project by running this command:

dotnet new mobileblazorbindings -o MyApp

Open the solution (SLN file) in Visual Studio and mark either the Android or iOS project as the StartUp Project, which should look like this:

VS solution with shared UI, Android, and iOS projects

Now run your first Mobile Blazor Bindings app in a local emulator or on an attached mobile device! Don’t have one set up yet for development? No worries, the Xamarin documentation has all the details for you here:

For documentation and walkthroughs, check out the Mobile Blazor Bindings documentation.

Why Mobile Blazor Bindings now?

Many developers delight in using XAML and Xamarin.Forms to craft beautiful native mobile apps. We have heard from a set of developers that come from a web programming background that having web specific patterns to build mobile applications would be ideal for them. The goal of these bindings is to see if developers would like to have the option of writing markup and doing data binding for native mobile applications using the Blazor-style programming model with Razor syntax and features. Would you love to see this option in the box for future versions of Visual Studio?

Learn more

To learn more about Experimental Mobile Blazor Bindings, please check out these resources:

Give feedback

Please send us your feedback via issues in our GitHub repo and by completing a short survey about your experience and expectations.

We hope you try out this new framework and let us know your thoughts!

Eilon Lipton

Posted on Leave a comment

Python Regex Fullmatch

Why have regular expressions survived seven decades of technological disruption? Because coders who understand regular expressions have a massive advantage when working with textual data. They can write in a single line of code what takes others dozens!

This article is all about the re.fullmatch(pattern, string) method of Python’s re library. There are three similar methods to help you use regular expressions:

  • The findall(pattern, string) method returns a list of string matches. Check out our blog tutorial.
  • The search(pattern, string) method returns a match object of the first match. Check out our blog tutorial.
  • The match(pattern, string) method returns a match object if the regex matches at the beginning of the string. Check out our blog tutorial.

So how does the re.fullmatch() method work? Let’s study the specification.

How Does re.fullmatch() Work in Python?

The re.fullmatch(pattern, string) method returns a match object if the pattern matches the whole string.

Specification:

re.fullmatch(pattern, string, flags=0)

The re.fullmatch() method has up to three arguments.

  • pattern: the regular expression pattern that you want to match.
  • string: the string which you want to search for the pattern.
  • flags (optional argument): a more advanced modifier that allows you to customize the behavior of the function. Want to know how to use those flags? Check out this detailed article on the Finxter blog.

We’ll explore them in more detail later.

Return Value:

The re.fullmatch() method returns a match object. You may ask (and rightly so):

What’s a Match Object?

If a regular expression matches a part of your string, there’s a lot of useful information that comes with it: what’s the exact position of the match? Which regex groups were matched—and where?

The match object is a simple wrapper for this information. Some regex methods of the re package in Python—such as fullmatch()—automatically create a match object upon the first pattern match.

At this point, you don’t need to explore the match object in detail. Just know that we can access the start and end positions of the match in the string by calling the methods m.start() and m.end() on the match object m:

>>> m = re.fullmatch('h...o', 'hello')
>>> m.start()
0
>>> m.end()
5

In the first line, you create a match object m by using the re.fullmatch() method. The pattern ‘h…o’ matches in the string ‘hello’ at start position 0 and end position 5. But note that as the fullmatch() method always attempts to match the whole string, the m.start() method will always return zero.

Now, you know the purpose of the match object in Python. Let’s check out a few examples of re.fullmatch()!

A Guided Example for re.fullmatch()

First, you import the re module and create the text string to be searched for the regex patterns:

>>> import re
>>> text = '''
Call me Ishmael. Some years ago--never mind how long precisely
--having little or no money in my purse, and nothing particular
to interest me on shore, I thought I would sail about a little
and see the watery part of the world. '''

Let’s say you want to match the full text with this regular expression:

>>> re.fullmatch('Call(.|\n)*', text)
>>> 

The first argument is the pattern to be found: 'Call(.|\n)*'. The second argument is the text to be analyzed. You stored the multi-line string in the variable text—so you take this as the second argument. The third argument flags of the fullmatch() method is optional and we skip it in the code.

There’s no output! This means that the re.fullmatch() method did not return a match object. Why? Because at the beginning of the string, there’s no match for the ‘Call’ part of the regex. The regex starts with an empty line!

So how can we fix this? Simple, by matching a new line character ‘\n’ at the beginning of the string.

>>> re.fullmatch('\nCall(.|\n)*', text)
<re.Match object; span=(0, 229), match='\nCall me Ishmael. Some years ago--never mind how>

The regex (.|\n)* matches an arbitrary number of characters (new line characters or not) after the prefix ‘\nCall’. This matches the whole text so the result is a match object. Note that there are 229 matching positions so the string included in resulting match object is only the prefix of the whole matching string. This fact is often overlooked by beginner coders.

What’s the Difference Between re.fullmatch() and re.match()?

The methods re.fullmatch() and re.match(pattern, string) both return a match object. Both attempt to match at the beginning of the string. The only difference is that re.fullmatch() also attempts to match the end of the string as well: it wants to match the whole string!

You can see this difference in the following code:

>>> text = 'More with less'
>>> re.match('More', text)
<re.Match object; span=(0, 4), match='More'>
>>> re.fullmatch('More', text)
>>> 

The re.match(‘More’, text) method matches the string ‘More’ at the beginning of the string ‘More with less’. But the re.fullmatch(‘More’, text) method does not match the whole text. Therefore, it returns the None object—nothing is printed to your shell!

What’s the Difference Between re.fullmatch() and re.findall()?

There are two differences between the re.fullmatch(pattern, string) and re.findall(pattern, string) methods:

  • re.fullmatch(pattern, string) returns a match object while re.findall(pattern, string) returns a list of matching strings.
  • re.fullmatch(pattern, string) can only match the whole string, while re.findall(pattern, string) can return multiple matches in the string.

Both can be seen in the following example:

>>> text = 'the 42th truth is 42'
>>> re.fullmatch('.*?42', text)
<re.Match object; span=(0, 20), match='the 42th truth is 42'>
>>> re.findall('.*?42', text)
['the 42', 'th truth is 42']

Note that the regex .*? matches an arbitrary number of characters but it attempts to consume as few characters as possible. This is called “non-greedy” match (the *? operator). The fullmatch() method only returns a match object that matches the whole string. The findall() method returns a list of all occurrences. As the match is non-greedy, it finds two such matches.

What’s the Difference Between re.fullmatch() and re.search()?

The methods re.fullmatch() and re.search(pattern, string) both return a match object. However, re.fullmatch() attempts to match the whole string while re.search() matches anywhere in the string.

You can see this difference in the following code:

>>> text = 'Finxter is fun!'
>>> re.search('Finxter', text)
<re.Match object; span=(0, 7), match='Finxter'>
>>> re.fullmatch('Finxter', text)
>>> 

The re.search() method retrieves the match of the ‘Finxter’ substring as a match object. But the re.fullmatch() method has no return value because the substring ‘Finxter’ does not match the whole string ‘Finxter is fun!’.

How to Use the Optional Flag Argument?

As you’ve seen in the specification, the fullmatch() method comes with an optional third ‘flag’ argument:

re.fullmatch(pattern, string, flags=0)

What’s the purpose of the flags argument?

Flags allow you to control the regular expression engine. Because regular expressions are so powerful, they are a useful way of switching on and off certain features (for example, whether to ignore capitalization when matching your regex).

Syntax Meaning
re.ASCII If you don’t use this flag, the special Python regex symbols w, W, b, B, d, D, s and S will match Unicode characters. If you use this flag, those special symbols will match only ASCII characters — as the name suggests.
re.A Same as re.ASCII
re.DEBUG If you use this flag, Python will print some useful information to the shell that helps you debugging your regex.
re.IGNORECASE If you use this flag, the regex engine will perform case-insensitive matching. So if you’re searching for [A-Z], it will also match [a-z].
re.I Same as re.IGNORECASE
re.LOCALE Don’t use this flag — ever. It’s depreciated—the idea was to perform case-insensitive matching depending on your current locale. But it isn’t reliable.
re.L Same as re.LOCALE
re.MULTILINE This flag switches on the following feature: the start-of-the-string regex ‘^’ matches at the beginning of each line (rather than only at the beginning of the string). The same holds for the end-of-the-string regex ‘$’ that now matches also at the end of each line in a multi-line string.
re.M Same as re.MULTILINE
re.DOTALL Without using this flag, the dot regex ‘.’ matches all characters except the newline character ‘n’. Switch on this flag to really match all characters including the newline character.
re.S Same as re.DOTALL
re.VERBOSE To improve the readability of complicated regular expressions, you may want to allow comments and (multi-line) formatting of the regex itself. This is possible with this flag: all whitespace characters and lines that start with the character ‘#’ are ignored in the regex.
re.X Same as re.VERBOSE

Here’s how you’d use it in a practical example:

>>> text = 'Python is great!'
>>> re.search('PYTHON', text, flags=re.IGNORECASE)
<re.Match object; span=(0, 6), match='Python'>

Although your regex ‘PYTHON’ is all-caps, we ignore the capitalization by using the flag re.IGNORECASE.

Where to Go From Here?

This article has introduced the re.fullmatch(pattern, string) method that attempts to match the whole string—and returns a match object if it succeeds or None if it doesn’t.

Learning Python is hard. But if you cheat, it isn’t as hard as it has to be:

Download 8 Free Python Cheat Sheets now!

Posted on Leave a comment

Python Regex Match

Why have regular expressions survived seven decades of technological disruption? Because coders who understand regular expressions have a massive advantage when working with textual data. They can write in a single line of code what takes others dozens!

This article is all about the match() method of Python’s re library. There are two similar methods to help you use regular expressions:

  • The easy-to-use but less powerful findall() method returns a list of string matches. Check out our blog tutorial.
  • The search() method returns a match object of the first match. Check out our blog tutorial.

So how does the re.match() method work? Let’s study the specification.

How Does re.match() Work in Python?

The re.match(pattern, string) method matches the pattern at the beginning of the string and returns a match object.

Specification:

re.match(pattern, string, flags=0)

The re.match() method has up to three arguments.

  • pattern: the regular expression pattern that you want to match.
  • string: the string which you want to search for the pattern.
  • flags (optional argument): a more advanced modifier that allows you to customize the behavior of the function. Want to know how to use those flags? Check out this detailed article on the Finxter blog.

We’ll explore them in more detail later.

Return Value:

The re.match() method returns a match object. You may ask (and rightly so):

What’s a Match Object?

If a regular expression matches a part of your string, there’s a lot of useful information that comes with it: what’s the exact position of the match? Which regex groups were matched—and where?

The match object is a simple wrapper for this information. Some regex methods of the re package in Python—such as match()—automatically create a match object upon the first pattern match.

At this point, you don’t need to explore the match object in detail. Just know that we can access the start and end positions of the match in the string by calling the methods m.start() and m.end() on the match object m:

>>> m = re.match('h...o', 'hello world')
>>> m.start()
0
>>> m.end()
5
>>> 'hello world'[m.start():m.end()] 'hello'

In the first line, you create a match object m by using the re.match() method. The pattern ‘h…o’ matches in the string ‘hello world’ at start position 0. You use the start and end position to access the substring that matches the pattern (using the popular Python technique of slicing). But note that as the match() method always attempts to match only at the beginning of the string, the m.start() method will always return zero.

Now, you know the purpose of the match() object in Python. Let’s check out a few examples of re.match()!

A Guided Example for re.match()

First, you import the re module and create the text string to be searched for the regex patterns:

>>> 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. '''

Let’s say you want to search the text for the string ‘her’:

>>> re.match('lips', text)
>>>

The first argument is the pattern to be found: the string ‘lips’. The second argument is the text to be analyzed. You stored the multi-line string in the variable text—so you take this as the second argument. The third argument flags of the match() method is optional.

There’s no output! This means that the re.match() method did not return a match object. Why? Because at the beginning of the string, there’s no match for the regex pattern ‘lips’.

So how can we fix this? Simple, by matching all the characters that preced the string ‘lips’ in the text:

>>> re.match('(.|\n)*lips', text)
<re.Match object; span=(0, 122), match="\n Ha! let me see her: out, alas! he's cold:\n>

The regex (.|\n)*lips matches all prefixes (an arbitrary number of characters including new lines) followed by the string ‘lips’. This results in a new match object that matches a huge substring from position 0 to position 122. Note that the match object doesn’t print the whole substring to the shell. If you access the matched substring, you’ll get the following result:

>>> m = re.match('(.|\n)*lips', text)
>>> text[m.start():m.end()] "\n Ha! let me see her: out, alas! he's cold:\n Her blood is settled, and her joints are stiff;\n Life and these lips"

Interestingly, you can also achieve the same thing by specifying the third flag argument as follows:

>>> m = re.match('.*lips', text, flags=re.DOTALL)
>>> text[m.start():m.end()] "\n Ha! let me see her: out, alas! he's cold:\n Her blood is settled, and her joints are stiff;\n Life and these lips"

The re.DOTALL flag ensures that the dot operator . matches all characters including the new line character.

What’s the Difference Between re.match() and re.findall()?

There are two differences between the re.match(pattern, string) and re.findall(pattern, string) methods:

  • re.match(pattern, string) returns a match object while re.findall(pattern, string) returns a list of matching strings.
  • re.match(pattern, string) returns only the first match in the string—and only at the beginning—while re.findall(pattern, string) returns all matches in the string.

Both can be seen in the following example:

>>> text = 'Python is superior to Python'
>>> re.match('Py...n', text)
<re.Match object; span=(0, 6), match='Python'>
>>> re.findall('Py...n', text)
['Python', 'Python']

The string ‘Python is superior to Python’ contains two occurrences of ‘Python’. The match() method only returns a match object of the first occurrence. The findall() method returns a list of all occurrences.

What’s the Difference Between re.match() and re.search()?

The methods re.search(pattern, string) and re.match(pattern, string) both return a match object of the first match. However, re.match() attempts to match at the beginning of the string while re.search() matches anywhere in the string.

You can see this difference in the following code:

>>> text = 'Slim Shady is my name'
>>> re.search('Shady', text)
<re.Match object; span=(5, 10), match='Shady'>
>>> re.match('Shady', text)
>>>

The re.search() method retrieves the match of the ‘Shady’ substring as a match object. But if you use the re.match() method, there is no match and no return value because the substring ‘Shady’ does not occur at the beginning of the string ‘Slim Shady is my name’.

How to Use the Optional Flag Argument?

As you’ve seen in the specification, the match() method comes with an optional third ‘flag’ argument:

re.match(pattern, string, flags=0)

What’s the purpose of the flags argument?

Flags allow you to control the regular expression engine. Because regular expressions are so powerful, they are a useful way of switching on and off certain features (for example, whether to ignore capitalization when matching your regex).

Syntax Meaning
re.ASCII If you don’t use this flag, the special Python regex symbols w, W, b, B, d, D, s and S will match Unicode characters. If you use this flag, those special symbols will match only ASCII characters — as the name suggests.
re.A Same as re.ASCII
re.DEBUG If you use this flag, Python will print some useful information to the shell that helps you debugging your regex.
re.IGNORECASE If you use this flag, the regex engine will perform case-insensitive matching. So if you’re searching for [A-Z], it will also match [a-z].
re.I Same as re.IGNORECASE
re.LOCALE Don’t use this flag — ever. It’s depreciated—the idea was to perform case-insensitive matching depending on your current locale. But it isn’t reliable.
re.L Same as re.LOCALE
re.MULTILINE This flag switches on the following feature: the start-of-the-string regex ‘^’ matches at the beginning of each line (rather than only at the beginning of the string). The same holds for the end-of-the-string regex ‘$’ that now matches also at the end of each line in a multi-line string.
re.M Same as re.MULTILINE
re.DOTALL Without using this flag, the dot regex ‘.’ matches all characters except the newline character ‘n’. Switch on this flag to really match all characters including the newline character.
re.S Same as re.DOTALL
re.VERBOSE To improve the readability of complicated regular expressions, you may want to allow comments and (multi-line) formatting of the regex itself. This is possible with this flag: all whitespace characters and lines that start with the character ‘#’ are ignored in the regex.
re.X Same as re.VERBOSE

Here’s how you’d use it in a practical example:

>>> text = 'Python is great!'
>>> re.search('PYTHON', text, flags=re.IGNORECASE)
<re.Match object; span=(0, 6), match='Python'>

Although your regex ‘PYTHON’ is all-caps, we ignore the capitalization by using the flag re.IGNORECASE.

Where to Go From Here?

This article has introduced the re.match(pattern, string) method that attempts to match the first occurrence of the regex pattern at the beginning of a given string—and returns a match object.

Python soars in popularity. There are two types of people: those who understand coding and those who don’t. The latter will have larger and larger difficulties participating in the era of massive adoption and penetration of digital content. Do you want to increase your Python skills daily without investing a lot of time?

Then join my “Coffee Break Python” email list of tens of thousands of ambitious coders!