Регулярные выражения в python
Содержание:
- And now for something completely different
- Regular Expression Patterns
- Major new features of the 3.9 series, compared to 3.8
- Группирующие скобки (…) и match-объекты в питоне
- Importance of Regular Expressions
- Major new features of the 3.8 series, compared to 3.7
- Разность re.match и re.search
- [Коллекция] Каковы различные квантификаторы Python Re?
- Modifying Strings¶
- Как сопоставить точечный персонаж (без особого значения)?
- Как работает метод findall () в Python?
- ChainMap objects¶
- Performance¶
- And Now For Something Completely Different
And now for something completely different
href=»http://www.montypython.net/scripts/galaxy.php»>Our universe itself keeps on expanding and expanding,
In all of the directions it can whiz;
As fast as it can go, at the speed of light, you know,
Twelve million miles a minute and that’s the fastest speed there is.
So remember, when you’re feeling very small and insecure,
How amazingly unlikely is your birth;
And pray that there’s intelligent life somewhere out in space,
‘Cause there’s bugger all down here on Earth!
Version | Operating System | Description | MD5 Sum | File Size | GPG |
---|---|---|---|---|---|
Gzipped source tarball | Source release | e2f52bcf531c8cc94732c0b6ff933ff0 | 24149103 | SIG | |
XZ compressed source tarball | Source release | 35b5a3d0254c1c59be9736373d429db7 | 18019640 | SIG | |
macOS 64-bit installer | macOS | for OS X 10.9 and later | 2f8a736eeb307a27f1998cfd07f22440 | 30238024 | SIG |
Windows help file | Windows | 3079d9cf19ac09d7b3e5eb3fb05581c4 | 8528031 | SIG | |
Windows x86-64 embeddable zip file | Windows | for AMD64/EM64T/x64 | 73bd7aab047b81f83e473efb5d5652a0 | 8168581 | SIG |
Windows x86-64 executable installer | Windows | for AMD64/EM64T/x64 | 0ba2e9ca29b719da6e0b81f7f33f08f6 | 27864320 | SIG |
Windows x86-64 web-based installer | Windows | for AMD64/EM64T/x64 | eeab52a08398a009c90189248ff43dac | 1364128 | SIG |
Windows x86 embeddable zip file | Windows | bc354669bffd81a4ca14f06817222e50 | 7305731 | SIG | |
Windows x86 executable installer | Windows | 959873b37b74c1508428596b7f9df151 | 26777232 | SIG | |
Windows x86 web-based installer | Windows | c813e6671f334a269e669d913b1f9b0d | 1328184 | SIG |
Regular Expression Patterns
Except for control characters, (+ ? . * ^ $ ( ) { } | \), all characters match themselves. You can escape a control character by preceding it with a backslash.
Following table lists the regular expression syntax that is available in Python −
Sr.No. | Pattern & Description |
---|---|
1 |
^ Matches beginning of line. |
2 |
$ Matches end of line. |
3 |
. Matches any single character except newline. Using m option allows it to match newline as well. |
4 |
Matches any single character in brackets. |
5 |
Matches any single character not in brackets |
6 |
re* Matches 0 or more occurrences of preceding expression. |
7 |
re+ Matches 1 or more occurrence of preceding expression. |
8 |
re? Matches 0 or 1 occurrence of preceding expression. |
9 |
re{ n} Matches exactly n number of occurrences of preceding expression. |
10 |
re{ n,} Matches n or more occurrences of preceding expression. |
11 |
re{ n, m} Matches at least n and at most m occurrences of preceding expression. |
12 |
a| b Matches either a or b. |
13 |
(re) Groups regular expressions and remembers matched text. |
14 |
(?imx) Temporarily toggles on i, m, or x options within a regular expression. If in parentheses, only that area is affected. |
15 |
(?-imx) Temporarily toggles off i, m, or x options within a regular expression. If in parentheses, only that area is affected. |
16 |
(?: re) Groups regular expressions without remembering matched text. |
17 |
(?imx: re) Temporarily toggles on i, m, or x options within parentheses. |
18 |
(?-imx: re) Temporarily toggles off i, m, or x options within parentheses. |
19 |
(?#…) Comment. |
20 |
(?= re) Specifies position using a pattern. Doesn’t have a range. |
21 |
(?! re) Specifies position using pattern negation. Doesn’t have a range. |
22 |
(?> re) Matches independent pattern without backtracking. |
23 |
\w Matches word characters. |
24 |
\W Matches nonword characters. |
25 |
\s Matches whitespace. Equivalent to . |
26 |
\S Matches nonwhitespace. |
27 |
\d Matches digits. Equivalent to . |
28 |
\D Matches nondigits. |
29 |
\A Matches beginning of string. |
30 |
\Z Matches end of string. If a newline exists, it matches just before newline. |
31 |
\z Matches end of string. |
32 |
\G Matches point where last match finished. |
33 |
\b Matches word boundaries when outside brackets. Matches backspace (0x08) when inside brackets. |
34 |
\B Matches nonword boundaries. |
35 |
\n, \t, etc. Matches newlines, carriage returns, tabs, etc. |
36 |
\1…\9 Matches nth grouped subexpression. |
37 |
\10 Matches nth grouped subexpression if it matched already. Otherwise refers to the octal representation of a character code. |
Major new features of the 3.9 series, compared to 3.8
Some of the new major new features and changes in Python 3.9 are:
- PEP 573, Module State Access from C Extension Methods
- PEP 584, Union Operators in
- PEP 585, Type Hinting Generics In Standard Collections
- PEP 593, Flexible function and variable annotations
- PEP 602, Python adopts a stable annual release cadence
- PEP 614, Relaxing Grammar Restrictions On Decorators
- PEP 615, Support for the IANA Time Zone Database in the Standard Library
- PEP 616, String methods to remove prefixes and suffixes
- PEP 617, New PEG parser for CPython
- BPO 38379, garbage collection does not block on resurrected objects;
- BPO 38692, os.pidfd_open added that allows process management without races and signals;
- BPO 39926, Unicode support updated to version 13.0.0;
- BPO 1635741, when Python is initialized multiple times in the same process, it does not leak memory anymore;
- A number of Python builtins (range, tuple, set, frozenset, list, dict) are now sped up using PEP 590 vectorcall;
- A number of Python modules (_abc, audioop, _bz2, _codecs, _contextvars, _crypt, _functools, _json, _locale, operator, resource, time, _weakref) now use multiphase initialization as defined by PEP 489;
- A number of standard library modules (audioop, ast, grp, _hashlib, pwd, _posixsubprocess, random, select, struct, termios, zlib) are now using the stable ABI defined by PEP 384.
You can find a more comprehensive list in this release’s «What’s New» document.
Группирующие скобки (…) и match-объекты в питоне
Match-объекты
Если функции , не находят соответствие шаблону в строке, то они возвращают , функция возващает пустой итератор.
Однако если соответствие найдено, то возвращается -объект.
Эта штука содержит в себе кучу полезной информации о соответствии шаблону.
В отличие от предыдущих функций, возвращает «простой и понятный» список соответствий.
Полный набор атрибутов -объекта можно посмотреть в , а здесь приведём самое полезное.
Метод | Описание | Пример |
---|---|---|
Подстрока, соответствующая всему шаблону | ||
Индекс в исходной строке, начиная с которого идёт найденная подстрока | ||
Индекс в исходной строке, который следует сразу за найденной подстрока |
Группирующие скобки
Если в шаблоне регулярного выражения встречаются скобки без , то они становятся группирующими.
В match-объекте, который возвращают , и , по каждой такой группе можно получить ту же информацию, что и по всему шаблону. А именно часть подстроки, которая соответствует , а также индексы начала и окончания в исходной строке. Достаточно часто это бывает полезно.
import re pattern = r'\s*(+)(\d+)\s*' string = r'--- Опять45 ---' match = re.search(pattern, string) print(f'Найдена подстрока >{match.group(0)}< с позиции {match.start(0)} до {match.end(0)}') print(f'Группа букв >{match.group(1)}< с позиции {match.start(1)} до {match.end(1)}') print(f'Группа цифр >{match.group(2)}< с позиции {match.start(2)} до {match.end(2)}') ### # Найдена подстрока > Опять45 < с позиции 3 до 16 # Группа букв >Опять< с позиции 6 до 11 # Группа цифр >45< с позиции 11 до 13
Тонкости со скобками и нумерацией групп.
Если к группирующим скобкам применён квантификатор (то есть указано число повторений), то подгруппа в match-объекте будет создана только для последнего соответствия.
Например, если бы в примере выше квантификаторы были снаружи от скобок , то вывод был бы таким:
Найдена подстрока > Опять45 < с позиции 3 до 16 Группа букв >ь< с позиции 10 до 11 Группа цифр >5< с позиции 12 до 13
Внутри группирующих скобок могут быть и другие группирующие скобки.
В этом случае их нумерация производится в соответствии с номером появления открывающей скобки с шаблоне.
import re pattern = r'((\d)(\d))((\d)(\d))' string = r'123456789' match = re.search(pattern, string) print(f'Найдена подстрока >{match.group(0)}< с позиции {match.start(0)} до {match.end(0)}') for i in range(1, match.groups()+1): print(f'Группа №{i} >{match.group(i)}< с позиции {match.start(i)} до {match.end(i)}') ### Найдена подстрока >1234< с позиции 0 до 4 Группа №1 >12< с позиции 0 до 2 Группа №2 >1< с позиции 0 до 1 Группа №3 >2< с позиции 1 до 2 Группа №4 >34< с позиции 2 до 4 Группа №5 >3< с позиции 2 до 3 Группа №6 >4< с позиции 3 до 4
Группы и
Если в шаблоне есть группирующие скобки, то вместо списка найденных подстрок будет возвращён список кортежей, в каждом из которых только соответствие каждой группе. Это не всегда происходит по плану, поэтому обычно нужно использовать негруппирующие скобки .
import re print(re.findall(r'(+)(\d*)', r'foo3, im12, go, 24buz42')) # ->
Группы и
Если в шаблоне нет группирующих скобок, то работает очень похожим образом на .
А вот если группирующие скобки в шаблоне есть, то между каждыми разрезанными строками будут все соответствия каждой из подгрупп.
import re print(re.split(r'(\s*)([+*/-])(\s*)', r'12 + 13*15 - 6')) # ->
Importance of Regular Expressions
In last few years, there has been a dramatic shift in usage of general purpose programming languages for data science and machine learning. This was not always the case – a decade back this thought would have met a lot of skeptic eyes!
This means that more people / organizations are using tools like Python / JavaScript for solving their data needs. This is where Regular Expressions become super useful. Regular expressions are normally the default way of data cleaning and wrangling in most of these tools. Be it extraction of specific parts of text from web pages, making sense of twitter data or preparing your data for text mining – Regular expressions are your best bet for all these tasks.
Given their applicability, it makes sense to know them and use them appropriately.
Major new features of the 3.8 series, compared to 3.7
- PEP 572, Assignment expressions
- PEP 570, Positional-only arguments
- PEP 587, Python Initialization Configuration (improved embedding)
- PEP 590, Vectorcall: a fast calling protocol for CPython
- PEP 578, Runtime audit hooks
- PEP 574, Pickle protocol 5 with out-of-band data
- Typing-related: PEP 591 (Final qualifier), PEP 586 (Literal types), and PEP 589 (TypedDict)
- Parallel filesystem cache for compiled bytecode
- Debug builds share ABI as release builds
- f-strings support a handy specifier for debugging
- is now legal in blocks
- on Windows, the default event loop is now
- on macOS, the spawn start method is now used by default in
- can now use shared memory segments to avoid pickling costs between processes
- is merged back to CPython
- is now 40% faster
- now uses Protocol 4 by default, improving performance
There are many other interesting changes, please consult the «What’s New» page in the documentation for a full list.
Разность re.match и re.search
re.match соответствует только начало строки, если начало строки не соответствует регулярному выражению, совпадение не найдено, функция возвращает None, и re.search совпадают со строкой, пока не найдет совпадения.
Пример:
#!/usr/bin/python3 import re line = "Cats are smarter than dogs"; matchObj = re.match( r'dogs', line, re.M|re.I) if matchObj: print ("match --> matchObj.group() : ", matchObj.group()) else: print ("No match!!") matchObj = re.search( r'dogs', line, re.M|re.I) if matchObj: print ("search --> matchObj.group() : ", matchObj.group()) else: print ("No match!!")
No match!! search --> matchObj.group() : dogs
[Коллекция] Каковы различные квантификаторы Python Re?
Если вы хотите использовать (и понимать) регулярные выражения на практике, вам нужно знать самые важные квантования, которые могут быть применены к любому Regeex (включая Regex dotex)!
Так что давайте погрузимся в другие регеисы:
Квантификатор
Описание
Пример
.
Wild-Card («DOT») соответствует любому символу в строке, кроме нового символа «\ N».
Regex ‘…’ соответствует всем словам с тремя символами, такими как «abc», «Cat» и «собака».
*
Звездочка нулевой или больше соответствует произвольному количеству вхождений (включая нулевые вхождения) непосредственно предшествующего Regex.
Regex ‘Cat *’ соответствует строкам «CA», «CAT», «CATT», «CATTT» и «CATTTTTTT». —
?
Матчи ноль или один (как следует из названия) либо ноль, либо в одних случаях непосредственно предшествующего Regex.
Regex ‘Cat?’ Соответствует обеим струнам «Ca» и «CAT» – но не «CATT», «CATTT» и «CATTTTTTT».
+
По меньшей мере, один соответствует одному или нескольким вхождению непосредственно предшествующего регеек.
Regex ‘Cat +’ не соответствует строке «CA», а соответствует всем строкам, по меньшей мере, одним задним характером «T», такими как «кошка», «CATT» и «CATTT».
^
Начальная строка соответствует началу строки.
Regex ‘^ p’ соответствует строкам «Python» и «программирование», но не «Lisp» и «шпионить», где символ «p» не происходит в начале строки.
$
Конец строки соответствует концу строки.
Regex ‘Py $’ будет соответствовать строкам «Main.py» и «Pypy», но не строки «Python» и «pypi».
A | B.
Или соответствует либо регезе A или REGEX B
Обратите внимание, что интуиция сильно отличается от стандартной интерпретации или оператора, который также может удовлетворить оба условия.
Regex ‘(Hello) | (Привет) «Соответствует строки« Hello World »и« Привет Python ». Было бы не иметь смысла попытаться сопоставить их обоих одновременно.
Аб
И совпадает с первым регелем А и второе регулярное выражение в этой последовательности.
Мы уже видели его тривиально в Regex ‘Ca’, которое соответствует первым Regex ‘C’ и Second Regex ‘A’.
Обратите внимание, что я дал вышеупомянутые операторы некоторых более значимых имен (жирным шрифтом), чтобы вы могли немедленно понять цель каждого Regex. Например, Оператор обычно обозначается как оператор «Caret»
Эти имена не описаны Поэтому я придумал более детские сады, такие как оператор «Пусковая строка».
Мы уже видели много примеров, но давайте погрузимся еще больше!
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!'. ''' print(re.findall('is.*and', text)) ''' Finds all occurrences of the word 'is', followed by an arbitrary number of characters and the word 'and'. ''' print(re.findall('her:?', text)) ''' Finds all occurrences of the word 'her', followed by zero or one occurrences of the colon ':'. ''' print(re.findall('her:+', text)) ''' Finds all occurrences of the word 'her', followed by one or more occurrences of the colon ':'. ''' 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. ''' print(re.findall('(Life|Death)', text)) ''' Finds all occurrences of either the word 'Life' or the word 'Death'. '''
В этих примерах вы уже видели специальный символ который обозначает нового стилевого символа в Python (и большинство других языках). Есть много специальных символов, специально предназначенных для регулярных выражений.
Modifying Strings¶
Up to this point, we’ve simply performed searches against a static string.
Regular expressions are also commonly used to modify strings in various ways,
using the following pattern methods:
Method/Attribute |
Purpose |
---|---|
Split the string into a list, splitting it |
|
Find all substrings where the RE matches, and |
|
Does the same thing as , but |
Splitting Strings
The method of a pattern splits a string apart
wherever the RE matches, returning a list of the pieces. It’s similar to the
method of strings but provides much more generality in the
delimiters that you can split by; string only supports splitting by
whitespace or by a fixed string. As you’d expect, there’s a module-level
function, too.
- (string, maxsplit=0)
-
Split string by the matches of the regular expression. If capturing
parentheses are used in the RE, then their contents will also be returned as
part of the resulting list. If maxsplit is nonzero, at most maxsplit splits
are performed.
You can limit the number of splits made, by passing a value for maxsplit.
When maxsplit is nonzero, at most maxsplit splits will be made, and the
remainder of the string is returned as the final element of the list. In the
following example, the delimiter is any sequence of non-alphanumeric characters.
>>> p = re.compile(r'\W+') >>> p.split('This is a test, short and sweet, of split().') >>> p.split('This is a test, short and sweet, of split().', 3)
Sometimes you’re not only interested in what the text between delimiters is, but
also need to know what the delimiter was. If capturing parentheses are used in
the RE, then their values are also returned as part of the list. Compare the
following calls:
>>> p = re.compile(r'\W+') >>> p2 = re.compile(r'(\W+)') >>> p.split('This... is a test.') >>> p2.split('This... is a test.')
The module-level function adds the RE to be used as the first
argument, but is otherwise the same.
>>> re.split(r'+', 'Words, words, words.') >>> re.split(r'(+)', 'Words, words, words.') >>> re.split(r'+', 'Words, words, words.', 1)
Как сопоставить точечный персонаж (без особого значения)?
Если вы используете символ В регулярном выражении Питон предполагает, что это точечный оператор, о котором вы говорите. Но что, если вы действительно хотите сопоставить точку, например, чтобы соответствовать периоду в конце предложения?
Ничего проще, чем это: избежать точечного регулятора, используя обратную косание: Отказ Обратная черта не обнаруживает значение специального символа в Regex. Двигатель Regex теперь знает, что вы на самом деле ищете точечный персонаж, а не произвольный символ, кроме новой строки.
Вот пример:
>>> import re >>> text = 'Python. Is. Great. Period.' >>> re.findall('\.', text)
Метод возвращает все четыре периода в предложении в качестве сопоставления подстроки для Regex Отказ
В этом примере вы узнаете, как вы можете объединить его с другими регулярными выражениями:
>>> re.findall('\.\s', text)
Теперь вы ищете период срока, а затем произвольный пробел. В тексте только три таких соответствующих подстроки.
В следующем примере вы узнаете, как объединить это с классом персонажа:
>>> re.findall('\.', text)
Вы хотите найти либо персонаж или характер сопровождается символом периода . Две подстроки соответствуют этому Regex.
Обратите внимание, что пропуская обратная косание требуется. Если вы забудете это, это может привести к странному поведению:
>>> re.findall('.', text)
Как произвольный символ разрешен после класса персонажа, подстрока также соответствует Regex.
Как работает метод findall () в Python?
Метод сканирует от слева направо , в поисках всех не перекрывающиеся матчи из . Возвращает Список строк в порядке сопоставления при сканировании строки слева направо.
Спецификация :
re.findall(pattern, string, flags=0)
Метод имеет до трех аргументов.
- : Регулярное выражение выражения, которое вы хотите сопоставить.
- : Строка, которую вы хотите искать шаблон.
- (Необязательный аргумент): более продвинутый модификатор, который позволяет настроить поведение функции. Хотите знать Как использовать эти флаги? Проверьте эту подробную статью на блог Finxter.
Мы посмотрим на каждого из них более подробно.
Возвращаемое значение:
Метод возвращает список строк. Каждый строковый элемент представляет собой соответствующую подстроку строкового аргумента.
Давайте проверим несколько примеров!
ChainMap objects¶
New in version 3.3.
A class is provided for quickly linking a number of mappings
so they can be treated as a single unit. It is often much faster than creating
a new dictionary and running multiple calls.
The class can be used to simulate nested scopes and is useful in templating.
- class (*maps)
-
A groups multiple dicts or other mappings together to
create a single, updateable view. If no maps are specified, a single empty
dictionary is provided so that a new chain always has at least one mapping.The underlying mappings are stored in a list. That list is public and can
be accessed or updated using the maps attribute. There is no other state.Lookups search the underlying mappings successively until a key is found. In
contrast, writes, updates, and deletions only operate on the first mapping.A incorporates the underlying mappings by reference. So, if
one of the underlying mappings gets updated, those changes will be reflected
in .All of the usual dictionary methods are supported. In addition, there is a
maps attribute, a method for creating new subcontexts, and a property for
accessing all but the first mapping:-
A user updateable list of mappings. The list is ordered from
first-searched to last-searched. It is the only stored state and can
be modified to change which mappings are searched. The list should
always contain at least one mapping.
- (m=None, **kwargs)
-
Returns a new containing a new map followed by
all of the maps in the current instance. If is specified,
it becomes the new map at the front of the list of mappings; if not
specified, an empty dict is used, so that a call to
is equivalent to: . If any keyword arguments
are specified, they update passed map or new empty dict. This method
is used for creating subcontexts that can be updated without altering
values in any of the parent mappings.Changed in version 3.4: The optional parameter was added.
Changed in version 3.10: Keyword arguments support was added.
-
Property returning a new containing all of the maps in
the current instance except the first one. This is useful for skipping
the first map in the search. Use cases are similar to those for the
keyword used in . The use cases also parallel those for the built-in
function. A reference to is equivalent to:
.
Note, the iteration order of a is determined by
scanning the mappings last to first:>>> baseline = {'music' 'bach', 'art' 'rembrandt'} >>> adjustments = {'art' 'van gogh', 'opera' 'carmen'} >>> list(ChainMap(adjustments, baseline))
This gives the same ordering as a series of calls
starting with the last mapping:>>> combined = baseline.copy() >>> combined.update(adjustments) >>> list(combined)
Changed in version 3.9: Added support for and operators, specified in PEP 584.
-
See also
-
The MultiContext class
in the Enthought CodeTools package has options to support
writing to any mapping in the chain. -
Django’s Context class
for templating is a read-only chain of mappings. It also features
pushing and popping of contexts similar to the
method and the
property. -
The Nested Contexts recipe has options to control
whether writes and other mutations apply only to the first mapping or to
any mapping in the chain. -
A greatly simplified read-only version of Chainmap.
Performance¶
This section discusses the performance of the provided concrete I/O
implementations.
Binary I/O
By reading and writing only large chunks of data even when the user asks for a
single byte, buffered I/O hides any inefficiency in calling and executing the
operating system’s unbuffered I/O routines. The gain depends on the OS and the
kind of I/O which is performed. For example, on some modern OSes such as Linux,
unbuffered disk I/O can be as fast as buffered I/O. The bottom line, however,
is that buffered I/O offers predictable performance regardless of the platform
and the backing device. Therefore, it is almost always preferable to use
buffered I/O rather than unbuffered I/O for binary data.
Text I/O
Text I/O over a binary storage (such as a file) is significantly slower than
binary I/O over the same storage, because it requires conversions between
unicode and binary data using a character codec. This can become noticeable
handling huge amounts of text data like large log files. Also,
and are both quite slow
due to the reconstruction algorithm used.
, however, is a native in-memory unicode container and will
exhibit similar speed to .
Multi-threading
objects are thread-safe to the extent that the operating system
calls (such as under Unix) they wrap are thread-safe too.
Binary buffered objects (instances of ,
, and )
protect their internal structures using a lock; it is therefore safe to call
them from multiple threads at once.
objects are not thread-safe.
Reentrancy
Binary buffered objects (instances of ,
, and )
are not reentrant. While reentrant calls will not happen in normal situations,
they can arise from doing I/O in a handler. If a thread tries to
re-enter a buffered object which it is already accessing, a
is raised. Note this doesn’t prohibit a different thread from entering the
buffered object.
The above implicitly extends to text files, since the function
will wrap a buffered object inside a . This includes
standard streams and therefore affects the built-in function as
well.
And Now For Something Completely Different
trong>Mr. Praline (John Cleese): ‘ELLO POLLY!!! Testing! Testing! This is your nine o’clock alarm call!
(Takes parrot out of the cage , throws it up in the air and watches it plummet to the floor.)
Mr. Praline: Now that’s what I call a dead parrot.
Owner (Michael Palin): No, no… No, he’s stunned!
Mr. Praline: STUNNED?!
Owner: Yeah! You stunned him, just as he was wakin’ up! Norwegian Blues stun easily, major.
Mr. Praline: Um… now look, mate. I’ve definitely ‘ad enough of this. That parrot is definitely deceased, and when I purchased it not ‘alf an hour ago, you assured me that its total lack of movement was due to it bein’ tired and shagged out following a prolonged squawk.
Owner: Well, he’s… he’s, ah… probably pining for the fjords.
Version | Operating System | Description | MD5 Sum | File Size | GPG |
---|---|---|---|---|---|
Gzipped source tarball | Source release | 83d71c304acab6c678e86e239b42fa7e | 24720640 | SIG | |
XZ compressed source tarball | Source release | d9eee4b20155553830a2025e4dcaa7b3 | 18433456 | SIG | |
macOS 64-bit Intel installer | macOS | for macOS 10.9 and later | 690ddb1be403a7efb202e93f3a994a49 | 29896827 | SIG |
macOS 64-bit universal2 installer | macOS | experimental, for macOS 11 Big Sur and later; recommended on Apple Silicon | ae8a1ae082074b260381c058d0336d05 | 37300939 | SIG |
Windows embeddable package (32-bit) | Windows | 659adf421e90fba0f56a9631f79e70fb | 7348969 | SIG | |
Windows embeddable package (64-bit) | Windows | 3acb1d7d9bde5a79f840167b166bb633 | 8211403 | SIG | |
Windows help file | Windows | a06af1ff933a13f6901a75e59247cf95 | 8597086 | SIG | |
Windows installer (32-bit) | Windows | b355cfc84b681ace8908ae50908e8761 | 27204536 | SIG | |
Windows installer (64-bit) | Windows | Recommended | 62cf1a12a5276b0259e8761d4cf4fe42 | 28296784 | SIG |