I need to match name objects according to pdf file specification. However, names may contain hexadecimal digits (preceded by #) to specify special characters. I would like to translate these matches to corresponding characters. Is there a clever way to do it without re-parsing the match string?
import re
Name = re.compile(r'''
(/ # Literal "/"
(?: #
(?:\#[A-Fa-f0-9]{2}) # Hex numbers
| #
[^\x00-\x20 \x23 \x2f \x7e-\xff] # Other
)+ #
) #
''', re.VERBOSE)
# some examples
names = """
The following are examples of valid literal names:
Raw string Translation
1. /Adobe#20Green -> "Adobe Green"
2. /PANTONE#205757#20CV -> "PANTONE 5757 CV"
3. /paired#28#29parentheses -> "paired( )parentheses"
4. /The_Key_of_F#23_Minor -> "The_Key_of_F#_Minor"
5. /A#42 -> "AB"
6. /Name1
7. /ASomewhatLongerName
8. /A;Name_With-Various***Characters?
9. /1.2
10. /$$
11. /@pattern
12. /.notdef
"""
Have a look at re.sub
.
You can use this with a function to match hex '#[0-9A-F]{2}' numbers and translate these using a function.
Eg
def hexrepl(m):
return chr(int(m.group(0)[1:3],16))
re.sub(r'#[0-9A-F]{2}', hexrepl, '/Adobe#20Green')
Will return '/Adobe Green'
I'd use finditer()
with a wrapper generator:
import re
from functools import partial
def _hexrepl(match):
return chr(int(match.group(1), 16))
unescape = partial(re.compile(r'#([0-9A-F]{2})').sub, _hexrepl)
def pdfnames(inputtext):
for match in Name.finditer(inputtext):
yield unescape(match.group(0))
Demo:
>>> for name in pdfnames(names):
... print name
...
/Adobe Green
/PANTONE 5757 CV
/paired()parentheses
/The_Key_of_F#_Minor
/AB
/Name1
/ASomewhatLongerName
/A;Name_With-Various***Characters?
/1.2
/$$
/@pattern
/.notdef
There is no more clever way that I know of; the re
engine cannot otherwise combine substitution and matching.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.