OpenOffice.org ODF, Python and XML
OpenOffice.org Writer showed what we expected. Both the double hyphen and the en dash changed into em dashes, and the starting double quote curves the right way.
Now, here's the rest. The expression to deal with the ending double quote is the mirror image of the starting double quote. In order to write an ending/closing double quote, we require the quote character either to be at the end of the string (\Z) or followed by whitespace. Again, when we do the replacement, we want to replace only the quote itself, not the whitespace. Hence, the Ending Double-quote PATtern (eDpat) is given by:
eDpat = re.compile(r'("\Z)|("(?=\s))', re.U)By the way, we compile all these patterns because we're going to use them over and over again when processing documents.
To handle single quotes ('like these'), we basically can do the same thing, except for a couple of issues. First, is the problem of contractions. When handling a double-quote character, we didn't cover the case where it was surrounded on both sides by non-whitespace. With single quotes (or apostrophes), we can't avoid that, because of words such as can't. Therefore, although the starting single-quote pattern can match the starting double-quote pattern, the other one, which doubles as an apostrophe in contractions, has a looser pattern. Here's what I came up with:
eSpat = re.compile(r"(?<=\S)'", re.U)
Because the pattern has an apostrophe in it, we delimit the pattern string using double-quote characters. This expression matches a single quote, but only when preceded immediately by a non-whitespace character.
The second issue, which the code doesn't address, is that of contractions beginning with an apostrophe, such as 'tis the season or stick 'em up.
The script treats the leading apostrophe like the start of a single-quoted phrase, and the single quote will face the wrong way. This probably will need a manual work-around.
Putting all this together, we have fix4.py:
#!/usr/bin/python -tt
import xml.dom.minidom
import sys
import re # new in fix3.py
DEBUG = 1
def dprint(what):
if DEBUG == 0: return
sys.stderr.write(what.encode('ascii',
'replace') + '\n')
emDash=u'\u2014'
enDash=u'\u2013' # new in fix3.py
sDquote=u'\u201c' # new in fix3.py
eDquote=u'\u201d' # new in fix4.py
sSquote=u'\u2018' # new in fix4.py
eSquote=u'\u2019' # new in fix4.py
# sDpat: pattern for starting dbl quote, as
# "Go! <-- the quote there
# We look for it either at start (\A) or
# after a space (\s), and we want it to be
# followed by a non-space
sDpat = re.compile(r'(\A|(?<=\s))"(?=\S)', re.U) # new in fix3.py
eDpat = re.compile(r'("\Z)|("(?=\s))', re.U) # new in fix4.py
sSpat = re.compile(r"(\A|(?<=\s))'(?=\S)", re.U) # new in fix4.py
eSpat = re.compile(r"(?<=\S)'", re.U) # new in fix4.py
def fixdata(td, depth):
dprint("depth=%d: childNode: %s" %
(depth, td.data))
# OK, so '--' becomes em dash everywhere
td.data = td.data.replace('--', emDash)
# Change 'en' dash to 'em' dash
td.data = td.data.replace(enDash , emDash) # new in fix3.py
# Make a nice starting curly-quote # new in fix3.py
td.data = sDpat.sub(sDquote, td.data) # new in fix3.py
td.data = eDpat.sub(eDquote, td.data) # new in fix4.py
# Make nice curly single-quote characters
td.data = sSpat.sub(sSquote, td.data) # new in fix4.py
td.data = eSpat.sub(eSquote, td.data) # new in fix4.py
def handle_xml_tree(aNode, depth):
if aNode.hasChildNodes():
for kid in aNode.childNodes:
handle_xml_tree(kid, depth+1)
else:
if 'data' in dir(aNode):
fixdata(aNode, depth)
def doit(argv):
doc = xml.dom.minidom.parse(argv[1])
handle_xml_tree(doc, 0)
sys.stdout.write(doc.toxml('utf-8'))
if __name__ == "__main__":
doit(sys.argv)
Let's try that on our example:
% ln -sf fix4.py fixit.py % ./fixit.sh ex3.odt ex3-4.odt depth=5: childNode: The ?en? dash ? is too short depth=5: childNode: The ?em? dash ? which is longer ? is what we need. depth=5: childNode: And two hyphens -- ugly -- should be turned into ?em? dashes. depth=5: childNode: This line has "straight double quotes" depth=5: childNode: These 'single quotes' aren't pretty. % oowriter ex3-4.odt
Let's review what we've done here:
Wrote scripts to unpack and repack ODF files.
Learned about using Python to understand the structure of ODF files.
Wrote a Python program to perform useful transformations on an OpenOffice.org Writer file, using regular expressions and the built-in string methods.
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.
Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.
Sponsored by ActiveState
| Containers—Not Virtual Machines—Are the Future Cloud | Jun 17, 2013 |
| Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer | Jun 12, 2013 |
| Weechat, Irssi's Little Brother | Jun 11, 2013 |
| One Tail Just Isn't Enough | Jun 07, 2013 |
| Introduction to MapReduce with Hadoop on Linux | Jun 05, 2013 |
| Android's Limits | Jun 04, 2013 |
- Containers—Not Virtual Machines—Are the Future Cloud
- Lock-Free Multi-Producer Multi-Consumer Queue on Ring Buffer
- Linux Systems Administrator
- Introduction to MapReduce with Hadoop on Linux
- Senior Perl Developer
- Technical Support Rep
- Weechat, Irssi's Little Brother
- UX Designer
- One Tail Just Isn't Enough
- Android's Limits
Featured Jobs
| Linux Systems Administrator | Houston and Austin, Texas | Host Gator |
| Senior Perl Developer | Austin, Texas | Host Gator |
| Technical Support Rep | Houston and Austin, Texas | Host Gator |
| UX Designer | Austin, Texas | Host Gator |
| Web & UI Developer (JavaScript & j Query) | Austin, Texas | Host Gator |
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?





18 min 30 sec ago
34 min 50 sec ago
1 hour 22 min ago
1 hour 23 min ago
3 hours 48 min ago
7 hours 58 min ago
8 hours 2 min ago
1 day 3 hours ago
1 day 4 hours ago
1 day 4 hours ago