>>> a_string = 'My alphabet starts where your alphabet ends.'
>>> a_string[3:11]
'alphabet'
>>> a_string[3:-3]
'alphabet starts where your alphabet en'
>>> a_string[0:2]
'My'
>>> a_string[:18]
'My alphabet starts'
>>> a_string[18:]
' where your alphabet ends.'
1. You can get a part of astring, called a “slice”, by specifying two indices. Thereturn value is a new string
containing all the characters of thestring, in order, starting with the first sliceindex.
2. Like slicing lists, you can use negative indices to slice strings.
3. Strings arezero-based, so
a_string[0:2]
returns the first two items of the string, starting at
a_string[0]
,up
to but not including
a_string[2]
.
4. If the left slice index is 0, you can leave it out, and 0 is implied. So
a_string[:18]
is the same as
a_string[0:18]
,because the starting 0 is implied.
5. Similarly, if the right slice index is the length of thestring, you can leave it out. So
a_string[18:]
is the
same as
a_string[18:44]
,because this string has 44 characters. There is a pleasing symmetry here. In this
44-character string,
a_string[:18]
returns the first 18 characters, and
a_string[18:]
returns everything but
the first 18 characters. In fact,
a_string[:n]
will always return the first
n
characters, and
a_string[n:]
will
return the rest, regardless of thelength of the string.
4.6. S
TRINGS VS
.B
YTES
Bytes are bytes; characters arean abstraction. An immutable sequenceof Unicode characters is called a
string. An immutablesequence of numbers-between-0-and-255 is called a bytesobject.
121
Pdf password remover - C# PDF Password Library: add, remove, edit PDF file password in C#.net, ASP.NET, MVC, WinForms, WPF
Help to Improve the Security of Your PDF Document by Setting Password
break password on pdf; copy from protected pdf
Pdf password remover - VB.NET PDF Password Library: add, remove, edit PDF file password in vb.net, ASP.NET, MVC, WinForms, WPF
Help to Improve the Security of Your PDF Document by Setting Password
pdf document password; creating password protected pdf
>>> by = b'abcd\x65'
>>> by
b'abcde'
>>> type(by)
<class 'bytes'>
>>> len(by)
5
>>> by += b'\xff'
>>> by
b'abcde\xff'
>>> len(by)
6
>>> by[0]
97
>>> by[0] = 102
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'bytes' object does not support item assignment
1. To define a
bytes
object, use the
b''
“byte literal” syntax. Each byte within the byte literal can bean
ASCII
character or an encoded hexadecimal number from
\x00
to
\xff
(0–255).
2. Thetypeof a
bytes
object is
bytes
.
3. Just like lists and strings, you can get the length of a
bytes
object with the built-in
len()
function.
4. Just like lists and strings, you can use the
+
operator to concatenate
bytes
objects. The result is a new
bytes
object.
5. Concatenating a5-byte
bytes
object and a 1-byte
bytes
object gives you a 6-byte
bytes
object.
6. Just like lists and strings, you can use index notation toget individual bytes in a
bytes
object. The items of a
string are strings; the items of a
bytes
object are integers. Specifically, integers between 0–255.
7. A
bytes
object is immutable; you can not assign individual bytes. If you need to change individual bytes, you
can either use
stringslicing and concatenation operators (which workthesameas strings), or you can
convert the
bytes
object into a
bytearray
object.
122
>>> by = b'abcd\x65'
>>> barr = bytearray(by)
>>> barr
bytearray(b'abcde')
>>> len(barr)
5
>>> barr[0] = 102
>>> barr
bytearray(b'fbcde')
1. To convert a
bytes
object intoa mutable
bytearray
object, use the built-in
bytearray()
function.
2. All the methods and operations you can do on a
bytes
object, you can do on a
bytearray
object too.
3. Theone difference is that, with the
bytearray
object, you can assign individual bytes using index notation.
Theassigned value must bean integer between 0–255.
Theone thing you can never do is mix bytes and strings.
>>> by = b'd'
>>> s = 'abcde'
>>> by + s
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't concat bytes to str
>>> s.count(by)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't convert 'bytes' object to str implicitly
>>> s.count(by.decode('ascii'))
1
1. You can’t concatenate bytes and strings. They are two different data types.
2. You can’t count the occurrences of bytes in a string, because there are no bytes in a string. A string is a
sequence of characters. Perhaps you meant “count theoccurrences of thestring that you would get after
123
decoding this sequenceof bytes in a particular character encoding”? Well then, you’ll need to say that
explicitly. Python 3 won’t implicitly convert bytes to strings or strings to bytes.
3. By an amazing coincidence, this line of code says “count theoccurrences of thestring that you would get
after decoding this sequence of bytes in this particular character encoding.”
And here is thelink between strings and bytes:
bytes
objects have a
decode()
method that takes a character
encoding and returns a string, and strings havean
encode()
method that takes acharacter encoding and
returns a
bytes
object. In theprevious example, the decoding was relatively straightforward—converting a
sequence of bytes in the
ASCII
encoding into astring of characters. But the same process works with any
encoding that supports thecharacters of the string—even legacy (non-Unicode) encodings.
>>> a_string = '深入 Python'
>>> len(a_string)
9
>>> by = a_string.encode('utf-8')
>>> by
b'\xe6\xb7\xb1\xe5\x85\xa5 Python'
>>> len(by)
13
>>> by = a_string.encode('gb18030')
>>> by
b'\xc9\xee\xc8\xeb Python'
>>> len(by)
11
>>> by = a_string.encode('big5')
>>> by
b'\xb2`\xa4J Python'
>>> len(by)
11
>>> roundtrip = by.decode('big5')
>>> roundtrip
'深入 Python'
>>> a_string == roundtrip
True
124
1. This is a string. It has ninecharacters.
2. This is a
bytes
object. It has 13 bytes. It is the sequence of bytes you get when you take
a_string
and
encodeit in
UTF
-8.
3. This is a
bytes
object. It has 11 bytes. It is the sequence of bytes you get when you take
a_string
and
encodeit in
GB18030.
4. This is a
bytes
object. It has 11 bytes. It is an entirely different sequence of bytes that you get when you take
a_string
and encode it in
Big5.
5. This is a string. It has ninecharacters. It is thesequence of characters you get when you take
by
and decode
it usingtheBig5 encoding algorithm. It is identical to the original string.
4.7.P
OSTSCRIPT
:C
HARACTER
E
NCODING
O
F
P
YTHON
S
OURCE
C
ODE
Python 3 assumes that your source code—i.e. each
.py
file—is encoded in
UTF
-8.
In Python 2, the default encoding for
.py
files was
ASCII
.In Python 3,
the default
encoding is
UTF
-8.
If you would liketo usea different encoding within your Python code, you can put an encoding declaration
on the first line of each file. This declaration defines a
.py
file to be windows-1252:
# -*- coding: windows-1252 -*-
Technically, thecharacter encoding override can also beon the second line, if the first line is a
UNIX
-like
hash-bang command.
#!/usr/bin/python3
# -*- coding: windows-1252 -*-
125
For more information, consult
PEP
263: Defining Python Source Code Encodings.
4.8.F
URTHER
R
EADING
On Unicode in Python:
Python Unicode HOWTO
What’s New In Python 3: Text vs. Data Instead Of Unicode vs. 8-bit
On Unicode in general:
TheAbsolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and
Character Sets (No Excuses!)
On theGoodness of Unicode
On Character Strings
Characters vs. Bytes
On character encoding in other formats:
Character encoding in XML
Character encoding in HTML
On strings and string formatting:
string
—Common string operations
Format String Syntax
Format Specification Mini-Language
PEP
3101: Advanced String Formatting
126
C
HAPTER
5. R
EGULAR
E
XPRESSIONS
Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two
problems.
Jamie Zawinski
5.1. D
IVING
I
N
E
very modern programming language has built-in functions for working with strings. In Python, strings
have methods for searching and replacing:
index()
,
find()
,
split()
,
count()
,
replace()
,
&
c. But these
methods arelimited to the simplest of cases. For example, the
index()
method looks for a single, hard-
coded substring, and the search is always case-sensitive. To do case-insensitive searches of a string
s
,you
must call
s.lower()
or
s.upper()
and make sure your search strings aretheappropriate case to match. The
replace()
and
split()
methods havethe same limitations.
If your goal can be accomplished with string methods, you should use them. They’re fast and simpleand easy
to read, and there’s a lot to be said for fast, simple, readablecode. But if you find yourself using a lot of
different string functions with
if
statements to handle special cases, or if you’rechaining calls to
split()
and
join()
to slice-and-dice your strings, you may need to move up to regular expressions.
Regular expressions area powerful and (mostly) standardized way of searching, replacing, and parsing text
with complex patterns of characters. Although the regular expression syntax is tight and unlike normal code,
the result can end up being more readable than a hand-rolled solution that uses a long chain of string
functions. There are even ways of embedding comments within regular expressions, so you can include fine-
grained documentation within them.
If you’ve used regular expressions in other languages (likePerl, JavaScript, or PHP),
Python’s syntax will bevery familiar. Read the summary of the
re
moduletoget an
overview of the available functions and their arguments.
127
5.2. C
ASE
S
TUDY
:S
TREET
A
DDRESSES
This series of examples was inspired by a real-life problem I had in my day job several years ago, when I
needed to scrub and standardize street addresses exported from a legacy system before importing them into
anewer system. (See, I don’t just make this stuff up;it’s actually useful.) This example shows how I
approached the problem.
>>> s = '100 NORTH MAIN ROAD'
>>> s.replace('ROAD', 'RD.')
'100 NORTH MAIN RD.'
>>> s = '100 NORTH BROAD ROAD'
>>> s.replace('ROAD', 'RD.')
'100 NORTH BRD. RD.'
>>> s[:-4] + s[-4:].replace('ROAD', 'RD.')
'100 NORTH BROAD RD.'
>>> import re
>>> re.sub('ROAD$', 'RD.', s)
'100 NORTH BROAD RD.'
1. My goal is tostandardize a street address so that
'ROAD'
is always abbreviated as
'RD.'
.At first glance, I
thought this was simple enough that I could just use the string method
replace()
.After all, all the data was
already uppercase, so casemismatches would not be a problem. And the search string,
'ROAD'
,was a
constant. And in this deceptively simpleexample,
s.replace()
does indeed work.
2. Life, unfortunately, is full of counterexamples, and I quickly discovered this one. Theproblem here is that
'ROAD'
appears twice in the address, once as part of the street name
'BROAD'
and once as its own word.
The
replace()
method sees thesetwo occurrences and blindly replaces both of them; meanwhile, I seemy
addresses getting destroyed.
3. To solve the problem of addresses with morethan one
'ROAD'
substring, you could resort to something like
this: only search and replace
'ROAD'
in the last four characters of the address (
s[-4:]
), and leavethestring
alone (
s[:-4]
). But you can seethat this is already getting unwieldy. For example, the pattern is dependent
on the length of the string you’re replacing. (If you werereplacing
'STREET'
with
'ST.'
,you would need to
128
^matches
the start of
astring. $
matches the
end of a
string.
use
s[:-6]
and
s[-6:].replace(...)
.) Would you liketo comeback in six months and debug this? I know I
wouldn’t.
4. It’s time to move up to regular expressions. In Python, all functionality related to regular expressions is
contained in the
re
module.
5. Take a look at the first parameter:
'ROAD$'
.This is a simple regular expression that matches
'ROAD'
only
when it occurs at the end of a string. The
$
means “end of thestring.” (There is a corresponding character,
the caret
^
,which means “beginningof thestring.”) Using the
re.sub()
function, you search the string
s
for
the regular expression
'ROAD$'
and replaceit with
'RD.'
.This matches the
ROAD
at theend of the string
s
,
but does not match the
ROAD
that’s part of the word
BROAD
,becausethat’s in themiddle of
s
.
Continuing with my story of scrubbing addresses, I soon
discovered that the previous example, matching
'ROAD'
at theend of the address, was not good enough,
becausenot all addresses included a street designation
at all. Some addresses simply ended with the street
name. I got away with it most of the time, but if the
street namewas
'BROAD'
,then the regular expression
would match
'ROAD'
at the end of the string as part of
the word
'BROAD'
,which is not what I wanted.
>>> s = '100 BROAD'
>>> re.sub('ROAD$', 'RD.', s)
'100 BRD.'
>>> re.sub('\\bROAD$', 'RD.', s)
'100 BROAD'
>>> re.sub(r'\bROAD$', 'RD.', s)
'100 BROAD'
>>> s = '100 BROAD ROAD APT. 3'
>>> re.sub(r'\bROAD$', 'RD.', s)
'100 BROAD ROAD APT. 3'
>>> re.sub(r'\bROAD\b', 'RD.', s)
'100 BROAD RD. APT 3'
129
1. What I really wanted was to match
'ROAD'
when it was at theend of the string and it was its own word
(and not a part of some larger word). To express this in a regular expression, you use
\b
,which means “a
word boundary must occur right here.” In Python, this is complicated by thefact that the
'\'
character in a
string must itself be escaped. This is sometimes referred to as the backslash plague, and it is onereason why
regular expressions are easier in Perl than in Python. On thedown side, Perl mixes regular expressions with
other syntax, so if you have a bug, it may be hard to tell whether it’s a bug in syntax or a bugin your
regular expression.
2. To work around the backslash plague, you can usewhat is called a raw string, by prefixing the string with the
letter
r
.This tells Python that nothing in this string should be escaped;
'\t'
is a tab character, but
r'\t'
is
really the backslash character
\
followed by the letter
t
.I recommend always using raw strings when dealing
with regular expressions; otherwise, things get tooconfusing too quickly (and regular expressions are
confusing enough already).
3. *sigh* Unfortunately, I soon found more cases that contradicted my logic. In this case, the street address
contained theword
'ROAD'
as a whole word by itself, but it wasn’t at theend, because the address had an
apartment number after thestreet designation. Because
'ROAD'
isn’t at thevery end of thestring, it doesn’t
match, so the entire call to
re.sub()
ends up replacing nothing at all, and you get the original string back,
which is not what you want.
4. To solve this problem, I removed the
$
character and added another
\b
.Now the regular expression reads
“match
'ROAD'
when it’s a whole word by itself anywhere in thestring,” whether at the end, the beginning,
or somewherein the middle.
5.3. C
ASE
S
TUDY
:R
OMAN
N
UMERALS
You’ve most likely seen Roman numerals, even if you didn’t recognize them. You may have seen them in
copyrights of old movies and television shows (“Copyright
MCMXLVI
”instead of “Copyright
1946
”), or on the
dedication walls of libraries or universities (“established
MDCCCLXXXVIII
”instead of “established
1888
”). You
may also have seen them in outlines and bibliographical references. It’s a system of representing numbers
that really does dateback to the ancient Roman empire (hencethename).
130
Documents you may be interested
Documents you may be interested