I'm trying to count items in a list of strings using count() function and sorting the results from largest to smallest. Although the function performs reasonably well on small lists, it does not scale up well at all, as can be seen in the small experiment below with just 5 cycles of doubling up the input length (the 6th cycle was taking too long to wait). Is there a way to optimize the first list comprehension or perhaps an alternative to count() that would scale up better?
import nltk
from operator import itemgetter
import time
t = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris. Integer in mauris eu nibh euismod gravida. Duis ac tellus et risus vulputate vehicula. Donec lobortis risus a elit. Etiam tempor. Ut ullamcorper, ligula eu tempor congue, eros est euismod turpis, id tincidunt sapien risus a quam. Maecenas fermentum consequat mi. Donec fermentum. Pellentesque malesuada nulla a mi. Duis sapien sem, aliquet nec, commodo eget, consequat quis, neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl adipiscing sapien, sed malesuada diam lacus eget erat. Cras mollis scelerisque nunc. Nullam arcu. Aliquam consequat. Curabitur augue lorem, dapibus quis, laoreet et, pretium ac, nisi. Aenean magna nisl, mollis quis, molestie eu, feugiat in, orci. In hac habitasse platea dictumst."
unigrams = nltk.word_tokenize(t.lower())
for size in range(1, 6):
unigrams = unigrams*size
start = time.time()
unigram_freqs = [unigrams.count(word) for word in unigrams]
freq_pairs = set((zip(unigrams, unigram_freqs)))
freq_pairs = sorted(freq_pairs, key=itemgetter(1))[::-1]
end = time.time()
time_elapsed = round(end-start, 3)
print("Runtime: " + str(time_elapsed) + "s for " + str(size) + "x the size")
# Runtime: 0.001s for 1x the size
# Runtime: 0.003s for 2x the size
# Runtime: 0.022s for 3x the size
# Runtime: 0.33s for 4x the size
# Runtime: 8.065s for 5x the size
Using Counter from collections and sorting by means of the member function "most_common()" I get pretty much 0 seconds regardless of size:
import nltk
nltk.download('punkt')
from operator import itemgetter
from collections import Counter
import time
t = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris. Integer in mauris eu nibh euismod gravida. Duis ac tellus et risus vulputate vehicula. Donec lobortis risus a elit. Etiam tempor. Ut ullamcorper, ligula eu tempor congue, eros est euismod turpis, id tincidunt sapien risus a quam. Maecenas fermentum consequat mi. Donec fermentum. Pellentesque malesuada nulla a mi. Duis sapien sem, aliquet nec, commodo eget, consequat quis, neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl adipiscing sapien, sed malesuada diam lacus eget erat. Cras mollis scelerisque nunc. Nullam arcu. Aliquam consequat. Curabitur augue lorem, dapibus quis, laoreet et, pretium ac, nisi. Aenean magna nisl, mollis quis, molestie eu, feugiat in, orci. In hac habitasse platea dictumst."
unigrams = nltk.word_tokenize(t.lower())
for size in range(1, 5):
unigrams = unigrams*size
start = time.time()
unigram_freqs = [unigrams.count(word) for word in unigrams]
freq_pairs = set((zip(unigrams, unigram_freqs)))
freq_pairs = sorted(freq_pairs, key=itemgetter(1))[::-1]
end = time.time()
time_elapsed = round(end-start, 3)
print("Slow Runtime: " + str(time_elapsed) + "s for " + str(size) + "x the size")
start = time.time()
a = Counter(unigrams).most_common()
#print(a)
end = time.time()
time_elapsed = round(end-start, 3)
print("Fast Runtime: " + str(time_elapsed) + "s for " + str(size) + "x the size")
Slow Runtime: 0.003s for 1x the size
Fast Runtime: 0.0s for 1x the size
Slow Runtime: 0.006s for 2x the size
Fast Runtime: 0.0s for 2x the size
Slow Runtime: 0.157s for 3x the size
Fast Runtime: 0.0s for 3x the size
Slow Runtime: 1.891s for 4x the size
Fast Runtime: 0.001s for 4x the size
Related
I have tried many methods but it hasn't worked for me. I want to split a text files lines into multiple chunks. Specifically 50 lines per chunk.
Like this [['Line1', 'Line2' -- up to 50] and so on.
data.txt (example):
Line2
Line2
Line3
Line4
Line5
Line6
Line7
Line8
Python code:
with open('data.txt', 'r') as file:
sample = file.readlines()
chunks = []
for i in range(0, len(sample), 3): # replace 3 with 50 in your case
chunks.append(sample[i:i+3]) # replace 3 with 50 in your case
chunks (in my example, chunks of 3 lines):
[['Line1\n', 'Line2\n', 'Line3\n'], ['Line4\n', 'Line5\n', 'Line6\n'], ['Line7\n', 'Line8']]
You can apply the string.rstrip('\n') method on those lines to remove the \n at the end.
Alternative:
Without reading the whole file in memory (better):
chunks = []
with open('data.txt', 'r') as file:
while True:
chunk = []
for i in range(3): # replace 3 with 50 in your case
line = file.readline()
if not line:
break
chunk.append(line)
# or 'chunk.append(line.rstrip('\n')) to remove the '\n' at the ends
if not chunk:
break
chunks.append(chunk)
print(chunks)
Produces same result
A good way to do it would be to create a generic generator function that could break any sequence up into chunks of any size. Here's what I mean:
from itertools import zip_longest
def grouper(n, iterable): # Generator function.
"s -> (s0, s1, ...sn-1), (sn, sn+1, ...s2n-1), (s2n, s2n+1, ...s3n-1), ..."
FILLER = object() # Unique object
for group in zip_longest(*([iter(iterable)]*n), fillvalue=FILLER):
limit = group.index(FILLER) if group[-1] is FILLER else len(group)
yield group[:limit] # Sliced to remove any filler.
if __name__ == '__main__':
from pprint import pprint
with open('lorem ipsum.txt') as inf:
for chunk in grouper(3, inf):
pprint(chunk, width=90)
If the lorem ipsum.txt file contained these lines:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis ut volutpat sem.
In felis nibh, efficitur id orci tristique, sollicitudin rhoncus nibh. In
elementum suscipit est, et varius mi aliquam ac. Duis fringilla neque urna,
dapibus volutpat ex ullamcorper eget. Duis in mauris vitae neque porttitor
facilisis. Nulla ornare leo ac nibh facilisis, in feugiat eros accumsan.
Suspendisse elementum elementum libero, sed tempor ex sollicitudin ac. Cras
pharetra, neque eu porttitor mattis, odio quam interdum diam, quis aliquam ex
arcu non nisl. Duis consequat lorem metus. Mauris vitae ex ante. Duis vehicula.
The result will be the following chunks each composed of 3 lines or less:
('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis ut volutpat sem.\n',
'In felis nibh, efficitur id orci tristique, sollicitudin rhoncus nibh. In\n',
'elementum suscipit est, et varius mi aliquam ac. Duis fringilla neque urna,\n')
('dapibus volutpat ex ullamcorper eget. Duis in mauris vitae neque porttitor\n',
'facilisis. Nulla ornare leo ac nibh facilisis, in feugiat eros accumsan.\n',
'Suspendisse elementum elementum libero, sed tempor ex sollicitudin ac. Cras\n')
('pharetra, neque eu porttitor mattis, odio quam interdum diam, quis aliquam ex\n',
'arcu non nisl. Duis consequat lorem metus. Mauris vitae ex ante. Duis vehicula.\n')
Update
If you want to remove the newline characters from the end of the lines of the file, you could do it with the same generic grouper() function by passing it a generator expression to preprocess the lines being read without needing to read them all into memory first:
if __name__ == '__main__':
from pprint import pprint
with open('lorem ipsum.txt') as inf:
lines = (line.rstrip() for line in inf) # Generator expr - cuz outer parentheses.
for chunk in grouper(3, lines):
pprint(chunk, width=90)
Output using generator expression:
('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis ut volutpat sem.',
'In felis nibh, efficitur id orci tristique, sollicitudin rhoncus nibh. In',
'elementum suscipit est, et varius mi aliquam ac. Duis fringilla neque urna,')
('dapibus volutpat ex ullamcorper eget. Duis in mauris vitae neque porttitor',
'facilisis. Nulla ornare leo ac nibh facilisis, in feugiat eros accumsan.',
'Suspendisse elementum elementum libero, sed tempor ex sollicitudin ac. Cras')
('pharetra, neque eu porttitor mattis, odio quam interdum diam, quis aliquam ex',
'arcu non nisl. Duis consequat lorem metus. Mauris vitae ex ante. Duis vehicula.')
You can split the text by each newline using the str.splitlines() method. Then, using a list comprehension, you can use list slices to slice the list at increments of the chunk_size (50 in your case). Below, I used 3 as the chunk_size variable, but you can replace that with 50:
text = '''Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate
velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum.'''
lines = text.splitlines()
chunk_size = 3
chunks = [lines[i: i + chunk_size] for i in range(0, len(lines), chunk_size)]
print(chunks)
Output:
[['Lorem ipsum dolor sit amet, consectetur adipiscing elit,', 'sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'Ut enim ad minim veniam,'],
['quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', 'Duis aute irure dolor in reprehenderit in voluptate', 'velit esse cillum dolore eu fugiat nulla pariatur.'],
['Excepteur sint occaecat cupidatat non proident,', 'sunt in culpa qui officia deserunt mollit anim id est laborum.']]
I've got an exercise where I have two text, "left" and "right".
I need to make a function to make them side by side given a width as parameter and all of this using itertools and textwrap.
Here's my code :
import textwrap
import itertools
def sidebyside(left,right,width=79):
width = round((width+1)/2)
leftwrapped = textwrap.wrap(left,width = width-1)
for i in range(0,len(leftwrapped)):
leftwrapped[i] = leftwrapped[i].ljust(width)
rightwrapped = textwrap.wrap(right,width = width-1)
for i in range(0,len(rightwrapped)):
rightwrapped[i] = rightwrapped[i].ljust(width)
pipes = ["|"]*max(len(leftwrapped),len(rightwrapped))
paragraph = itertools.zip_longest(leftwrapped,pipes,rightwrapped, fillvalue="".ljust(width))
result = ""
for a in paragraph:
result = result + a[0] + a[1] + a[2] + "\n"
return(result)
Here's a sample of "left" & "right" :
left = (
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Sed non risus. "
"Suspendisse lectus tortor, dignissim sit amet, "
"adipiscing nec, utilisez sed sin dolor."
)
right = (
"Morbi venenatis, felis nec pretium euismod, "
"est mauris finibus risus, consectetur laoreet "
"sem enim sed arcu. Maecenas sit amet eleifend sem. "
"Nullam ac libero metus. Praesent ac finibus nulla, vitae molestie dolor."
" Aliquam vestibulum viverra nisl, id porta mi viverra hendrerit."
" Ut et porta augue, et convallis ante."
)
My problem is that I'm getting some spacing issues, i.e: for the first line, for a given length of 20, I have this output :
'Lorem |Morbi ven '
But I need this output :
'Lorem |Morbi ven'
Found it, my round function was not good, I had to make two width, the first one being the round of the division and a second one being the result of width - round(width/2).
Talk is cheap, code is better :
from itertools import zip_longest
import textwrap
def sidebyside(left, right, width=79):
mid_width = (width - (1 - width%2)) // 2
return "\n".join(
f"{l.ljust(mid_width)}|{r.ljust(mid_width)}"
for l, r in zip_longest(
*map(lambda t: textwrap.wrap("".join(t), mid_width), (left, right)),
fillvalue=""
)
)
The goal of the original post was to solve a programming puzzle that required the sidebyside() method be implemented using only itertools.zip_longest() and textwrap.wrap().
This method works but has some disadvantages. For instance, it does not support line breaks, within the left and right texts (all spacing is removed before the texts are reflowed to be side-by-side).
Since this is a really useful method, I wrote an improved version of it, see the Gist itself for more information.
For example:
# some random text
LOREM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
# split into paragraphs
LOREM_PARA = LOREM.replace(". ", ".\n\n").split("\n")
# arbitrarily truncate the first two lines for text B
TEXT_A = LOREM_PARA[:]
TEXT_B = LOREM_PARA[2:]
# reflow as side-by-side
print(side_by_side(TEXT_A, TEXT_B, width=50, as_string=True))
will output:
Lorem ipsum dolor sit | Ut enim ad minim
amet, consectetur | veniam, quis nostrud
adipiscing elit, sed do | exercitation ullamco
eiusmod tempor | laboris nisi ut aliquip
incididunt ut labore et | ex ea commodo
dolore magna aliqua. | consequat.
|
Ut enim ad minim | Duis aute irure dolor
veniam, quis nostrud | in reprehenderit in
exercitation ullamco | voluptate velit esse
laboris nisi ut aliquip | cillum dolore eu fugiat
ex ea commodo | nulla pariatur.
consequat. |
| Excepteur sint occaecat
Duis aute irure dolor | cupidatat non proident,
in reprehenderit in | sunt in culpa qui
voluptate velit esse | officia deserunt mollit
cillum dolore eu fugiat | anim id est laborum.
nulla pariatur. |
|
Excepteur sint occaecat |
cupidatat non proident, |
sunt in culpa qui |
officia deserunt mollit |
anim id est laborum. |
In wxpython the default behavior of a TextCtrl context menu is that the caret moves to the position in the TextCtrl that was right-clicked. When I overwrite the EVT_CONTEXT_MENU event and create my own menu, this behavior is missing. Is there an easy way to change this?
My objective is to allow tagging the right-clicked sentence or paragraph, but the current behavior requires the user to first left click the relevant sentence/paragraph to move the caret, then right click to select how much to tag.
Relevant code:
self.textbox.Bind(wx.EVT_CONTEXT_MENU, self.textbox_context_menu)
def textbox_context_menu(self, event):
""" show context menu when right-clicking on text """
menu = wx.Menu()
menu.Append(self.mark_sentence_id, "mark sentence")
menu.Append(self.mark_paragraph_id, "mark paragraph")
self.PopupMenu(menu)
EDIT: Here a minimalistic example that can be executed:
import wx
import wx.richtext as rt
class MCVE(wx.App):
""" App """
def OnInit(self):
frame = Frame()
frame.Show()
return True
class Frame(wx.Frame):
""" Frame """
def __init__(self):
style = wx.SYSTEM_MENU | wx.CAPTION | wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.RESIZE_BORDER
super(Frame, self).__init__(parent=None, title="LabelingTool", style=style, size=(800, 600))
self.panel = Panel(parent=self)
class Panel(wx.Panel):
""" Panel """
def __init__(self, parent):
super(Panel, self).__init__(parent)
# textbox
hboxsizer = wx.BoxSizer(wx.HORIZONTAL)
text = "Lorem Ipsum\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eget enim vitae elit convallis ultrices. Sed vestibulum in metus id tempus. Phasellus tincidunt risus elit, id sagittis erat placerat quis. Donec ac porta tortor, non varius purus. Suspendisse euismod auctor maximus. Suspendisse nec orci vel dui posuere ultrices. Vivamus dictum vel enim nec interdum. Nunc tincidunt nulla sed facilisis suscipit. Nunc eget nisi ut turpis venenatis faucibus.\n\nInteger mauris nulla, malesuada quis lacus vitae, condimentum tincidunt dui. Aliquam non nisi aliquam, vulputate dolor ut, fringilla ligula. Nulla vitae tellus sit amet nulla ultrices pellentesque eu vitae lectus. Aliquam fringilla mauris tortor, et maximus lorem bibendum quis. Nam in magna gravida, accumsan libero accumsan, feugiat nisl. Donec tincidunt, tortor ut aliquam convallis, urna odio imperdiet ligula, dignissim vulputate ligula diam sit amet tortor. Ut a eros risus.\n\nCras et erat sodales, tempus nulla a, vulputate metus. Maecenas lacinia, nulla ac congue pharetra, lorem nibh pharetra metus, eu porttitor turpis leo ut lectus. Proin luctus rutrum mi id pharetra. Suspendisse aliquet id est nec efficitur. Maecenas dolor dui, vulputate et pulvinar at, venenatis id lorem. Praesent vel nisi ultrices massa rhoncus vestibulum. Nunc imperdiet consectetur pharetra. In cursus nec massa nec finibus. Aliquam et ligula bibendum, sodales mauris a, efficitur sapien. Ut mattis et ipsum eget sodales. Vestibulum maximus libero id ipsum placerat interdum at luctus risus. In finibus accumsan nunc, vitae posuere est interdum quis. Vivamus sed neque metus. Etiam fringilla efficitur lacus, vel aliquam purus lobortis vitae. Donec ut placerat orci. Etiam efficitur efficitur eleifend.\n\nAenean in imperdiet nisl. Donec dapibus neque tincidunt, fringilla velit vel, vestibulum velit. Sed at lorem id tortor accumsan interdum eu ut orci. Aenean convallis aliquet libero eu congue. In dapibus posuere massa, quis finibus neque volutpat et. Integer non massa tristique, gravida justo id, accumsan nibh. Ut ac nisl purus. Integer vestibulum sem in ante pellentesque, ac interdum augue faucibus.\n\nInteger bibendum eros vitae aliquam venenatis. Integer feugiat orci eu metus placerat, ut dictum leo posuere. Vivamus eget ligula vitae ante porttitor cursus. Nulla consectetur enim eu nisi aliquam mollis. Aliquam elementum consequat mauris, dignissim tempus libero sodales eu. In ultrices ullamcorper nulla, vel aliquet est vestibulum non. Nullam nec est ante. Phasellus eleifend lacinia nulla nec ultricies."
self.textbox = rt.RichTextCtrl(parent=self, value=text, style=wx.TE_MULTILINE | wx.TE_READONLY)
self.textbox.Bind(wx.EVT_CONTEXT_MENU, self.textbox_context_menu)
hboxsizer.Add(self.textbox, proportion=1, flag=wx.EXPAND)
self.SetSizerAndFit(hboxsizer)
# event handling
self.tag_sentence_id = 100
self.tag_paragraph_id = 200
self.Bind(wx.EVT_MENU, self.menu_event)
def textbox_context_menu(self, event):
""" show context menu when right-clicking on text """
menu = wx.Menu()
menu.Append(self.tag_sentence_id, "tag sentence")
menu.Append(self.tag_paragraph_id, "tag paragraph")
self.PopupMenu(menu)
def menu_event(self, event):
""" handle context menu events """
event_id = event.GetId()
self.tag(event_id)
def tag(self, event_id):
# get caret position
caret_position = self.textbox.GetCaretPosition()+1
# tag by event
if event_id == self.tag_paragraph_id:
paragraph = self.find_paragraph(caret_position)
start = self.textbox.GetValue().find(paragraph)
end = start + len(paragraph)
self.apply_tag((start, end))
elif event_id == self.tag_sentence_id:
sentence = self.find_sentence(caret_position)
start = self.textbox.GetValue().find(sentence.strip())
end = start + len(sentence.strip())
self.apply_tag((start, end))
def apply_tag(self, position):
self.textbox.SetStyle(position[0], position[1], wx.TextAttr(colText=wx.WHITE, colBack=wx.BLACK))
def find_paragraph(self, caret_position):
paragraphs = self.textbox.GetValue().split("\n\n")
for paragraph in paragraphs:
paragraph = paragraph.strip()
start = self.textbox.GetValue().find(paragraph)
end = start + len(paragraph)
if start < caret_position < end:
return paragraph
def find_sentence(self, caret_position):
sentences = self.find_paragraph(caret_position).split(".")
for sentence in sentences:
sentence = sentence.strip()
start = self.textbox.GetValue().find(sentence)
end = start + len(sentence)
# append dot if applicable
if self.textbox.GetValue()[end] == ".":
sentence += "."
if start < caret_position < end:
return sentence
if __name__ == "__main__":
app = MCVE()
app.MainLoop()
If you comment out the line self.textbox.Bind(wx.EVT_CONTEXT_MENU, self.textbox_context_menu) you get the default context menu with the desired behavior of moving the caret to the right-clicked position in the text before opening the context menu, which allows for "tagging" the right-clicked sentence/paragraph without left-clicking first.
Use SetContextMenu and create menu before hand
import wx
import wx.richtext as rt
class MCVE(wx.App):
""" App """
def OnInit(self):
frame = Frame()
frame.Show()
return True
class Frame(wx.Frame):
""" Frame """
def __init__(self):
style = wx.SYSTEM_MENU | wx.CAPTION | wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.RESIZE_BORDER
super(Frame, self).__init__(parent=None, title="LabelingTool", style=style, size=(800, 600))
self.panel = Panel(parent=self)
class Panel(wx.Panel):
""" Panel """
def __init__(self, parent):
super(Panel, self).__init__(parent)
# textbox
hboxsizer = wx.BoxSizer(wx.HORIZONTAL)
text = "Lorem Ipsum\n\nLorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eget enim vitae elit convallis ultrices. Sed vestibulum in metus id tempus. Phasellus tincidunt risus elit, id sagittis erat placerat quis. Donec ac porta tortor, non varius purus. Suspendisse euismod auctor maximus. Suspendisse nec orci vel dui posuere ultrices. Vivamus dictum vel enim nec interdum. Nunc tincidunt nulla sed facilisis suscipit. Nunc eget nisi ut turpis venenatis faucibus.\n\nInteger mauris nulla, malesuada quis lacus vitae, condimentum tincidunt dui. Aliquam non nisi aliquam, vulputate dolor ut, fringilla ligula. Nulla vitae tellus sit amet nulla ultrices pellentesque eu vitae lectus. Aliquam fringilla mauris tortor, et maximus lorem bibendum quis. Nam in magna gravida, accumsan libero accumsan, feugiat nisl. Donec tincidunt, tortor ut aliquam convallis, urna odio imperdiet ligula, dignissim vulputate ligula diam sit amet tortor. Ut a eros risus.\n\nCras et erat sodales, tempus nulla a, vulputate metus. Maecenas lacinia, nulla ac congue pharetra, lorem nibh pharetra metus, eu porttitor turpis leo ut lectus. Proin luctus rutrum mi id pharetra. Suspendisse aliquet id est nec efficitur. Maecenas dolor dui, vulputate et pulvinar at, venenatis id lorem. Praesent vel nisi ultrices massa rhoncus vestibulum. Nunc imperdiet consectetur pharetra. In cursus nec massa nec finibus. Aliquam et ligula bibendum, sodales mauris a, efficitur sapien. Ut mattis et ipsum eget sodales. Vestibulum maximus libero id ipsum placerat interdum at luctus risus. In finibus accumsan nunc, vitae posuere est interdum quis. Vivamus sed neque metus. Etiam fringilla efficitur lacus, vel aliquam purus lobortis vitae. Donec ut placerat orci. Etiam efficitur efficitur eleifend.\n\nAenean in imperdiet nisl. Donec dapibus neque tincidunt, fringilla velit vel, vestibulum velit. Sed at lorem id tortor accumsan interdum eu ut orci. Aenean convallis aliquet libero eu congue. In dapibus posuere massa, quis finibus neque volutpat et. Integer non massa tristique, gravida justo id, accumsan nibh. Ut ac nisl purus. Integer vestibulum sem in ante pellentesque, ac interdum augue faucibus.\n\nInteger bibendum eros vitae aliquam venenatis. Integer feugiat orci eu metus placerat, ut dictum leo posuere. Vivamus eget ligula vitae ante porttitor cursus. Nulla consectetur enim eu nisi aliquam mollis. Aliquam elementum consequat mauris, dignissim tempus libero sodales eu. In ultrices ullamcorper nulla, vel aliquet est vestibulum non. Nullam nec est ante. Phasellus eleifend lacinia nulla nec ultricies."
self.textbox = rt.RichTextCtrl(parent=self, value=text, style=wx.TE_MULTILINE | wx.TE_READONLY)
# event handling
self.tag_sentence_id = 100
self.tag_paragraph_id = 200
self.menu = wx.Menu()
self.menu.Append(self.tag_sentence_id, "tag sentence")
self.menu.Append(self.tag_paragraph_id, "tag paragraph")
self.textbox.SetContextMenu(self.menu)
hboxsizer.Add(self.textbox, proportion=1, flag=wx.EXPAND)
self.SetSizerAndFit(hboxsizer)
self.Bind(wx.EVT_MENU, self.menu_event)
def menu_event(self, event):
""" handle context menu events """
event_id = event.GetId()
self.tag(event_id)
def tag(self, event_id):
# get caret position
caret_position = self.textbox.GetCaretPosition()+1
# tag by event
if event_id == self.tag_paragraph_id:
paragraph = self.find_paragraph(caret_position)
start = self.textbox.GetValue().find(paragraph)
end = start + len(paragraph)
self.apply_tag((start, end))
elif event_id == self.tag_sentence_id:
sentence = self.find_sentence(caret_position)
start = self.textbox.GetValue().find(sentence.strip())
end = start + len(sentence.strip())
self.apply_tag((start, end))
def apply_tag(self, position):
self.textbox.SetStyle(position[0], position[1], wx.TextAttr(colText=wx.WHITE, colBack=wx.BLACK))
def find_paragraph(self, caret_position):
paragraphs = self.textbox.GetValue().split("\n\n")
for paragraph in paragraphs:
paragraph = paragraph.strip()
start = self.textbox.GetValue().find(paragraph)
end = start + len(paragraph)
if start < caret_position < end:
return paragraph
def find_sentence(self, caret_position):
sentences = self.find_paragraph(caret_position).split(".")
for sentence in sentences:
sentence = sentence.strip()
start = self.textbox.GetValue().find(sentence)
end = start + len(sentence)
# append dot if applicable
if self.textbox.GetValue()[end] == ".":
sentence += "."
if start < caret_position < end:
return sentence
if __name__ == "__main__":
app = MCVE()
app.MainLoop()
How do you load and dump YAML using PyYAML, so that it uses the original styling as closely as possible?
I have Python to load and dump YAML data like:
import sys
import yaml
def _represent_dictorder(self, data):
# Maintains ordering of specific dictionary keys in the YAML output.
_data = []
ordering = ['questions', 'tags', 'answers', 'weight', 'date', 'text']
for key in ordering:
if key in data:
_data.append((str(key), data.pop(key)))
if data:
_data.extend(data.items())
return self.represent_mapping(u'tag:yaml.org,2002:map', _data)
yaml.add_representer(dict, _represent_dictorder)
text="""- questions:
- Lorem ipsum dolor sit amet, consectetur adipiscing elit.
tags:
context: curabitur
answers:
- weight: 2
date: 2014-1-19
text: |-
1. Mauris lorem magna, auctor et tristique id, fringilla ut metus.
2. Donec pellentesque elit non felis feugiat, in gravida ex hendrerit.
3. Mauris quis velit sapien. Nullam blandit, diam et pharetra maximus, mi erat scelerisque turpis, eu vestibulum dui ligula non lectus.
a. Aenean consectetur eleifend accumsan.
4. In erat lacus, egestas ut tincidunt ac, congue quis elit. Suspendisse semper purus ac turpis maximus dignissim.
a. Proin nec neque convallis, placerat odio non, suscipit erat. Nulla nec mattis nibh, accumsan feugiat felis.
5. Mauris lorem magna, auctor et tristique id, fringilla ut metus.
a. Morbi non arcu odio. Maecenas faucibus urna et leo euismod placerat.
b. Nulla facilisi. Pellentesque at pretium nunc.
c. Ut ipsum nibh, suscipit a pretium eu, eleifend vitae purus.
"""
yaml.dump(yaml.load(text), stream=sys.stdout, default_flow_style=False, indent=4)
but this outputs the YAML in a different style, like:
- questions:
- Lorem ipsum dolor sit amet, consectetur adipiscing elit.
tags:
context: curabitur
answers:
- weight: 2
date: 2014-1-19
text: "1. Mauris lorem magna, auctor et tristique id, fringilla ut metus.\n\
2. Donec pellentesque elit non felis feugiat, in gravida ex hendrerit.\n\
3. Mauris quis velit sapien. Nullam blandit, diam et pharetra maximus,\
\ mi erat scelerisque turpis, eu vestibulum dui ligula non lectus.\n \
\ a. Aenean consectetur eleifend accumsan.\n4. In erat lacus, egestas\
\ ut tincidunt ac, congue quis elit. Suspendisse semper purus ac turpis\
\ maximus dignissim.\n a. Proin nec neque convallis, placerat odio\
\ non, suscipit erat. Nulla nec mattis nibh, accumsan feugiat felis.\n\
5. Mauris lorem magna, auctor et tristique id, fringilla ut metus.\n \
\ a. Morbi non arcu odio. Maecenas faucibus urna et leo euismod placerat.\n\
\ b. Nulla facilisi. Pellentesque at pretium nunc.\n c. Ut ipsum\
\ nibh, suscipit a pretium eu, eleifend vitae purus."
As you can see, it's changing the style of the text-block, so that newlines are escaped, making it a lot harder to read.
So I tried specifying the default_style attribute like:
yaml.dump(yaml.load(text), stream=sys.stdout, default_flow_style=False, default_style='|', indent=4)
And that fixed the text-block style, but then it broke other styles by putting quotes around all other strings, adding newlines to single-line strings, and munging integers, like:
- "questions":
- |-
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
"tags":
"context": |-
curabitur
"answers":
- "weight": !!int |-
2
"date": |-
2014-1-19
"text": |-
1. Mauris lorem magna, auctor et tristique id, fringilla ut metus.
2. Donec pellentesque elit non felis feugiat, in gravida ex hendrerit.
3. Mauris quis velit sapien. Nullam blandit, diam et pharetra maximus, mi erat scelerisque turpis, eu vestibulum dui ligula non lectus.
a. Aenean consectetur eleifend accumsan.
4. In erat lacus, egestas ut tincidunt ac, congue quis elit. Suspendisse semper purus ac turpis maximus dignissim.
a. Proin nec neque convallis, placerat odio non, suscipit erat. Nulla nec mattis nibh, accumsan feugiat felis.
5. Mauris lorem magna, auctor et tristique id, fringilla ut metus.
a. Morbi non arcu odio. Maecenas faucibus urna et leo euismod placerat.
b. Nulla facilisi. Pellentesque at pretium nunc.
c. Ut ipsum nibh, suscipit a pretium eu, eleifend vitae purus.
How do I fix this so the output resembles the style of my original input?
How would you determine what string to represent as a block literal (or a folded block for that matter) and what to represent inline?
Under the assumption that you only want block literals used with strings that span over multiple lines, you can write your own string representer to switch between the styles based on the string content:
def selective_representer(dumper, data):
return dumper.represent_scalar(u"tag:yaml.org,2002:str", data,
style="|" if "\n" in data else None)
yaml.add_representer(str, selective_representer)
Now if you dump your data with default flow style set to False (to prevent dict/list inlining):
yaml.dump(yaml.load(text), stream=sys.stdout, default_flow_style=False, indent=4)
Your scalars will act as you expect them to.
I am working with python 3.4 in windows 7.Trying to compare two text files and i want to report the differences in them using difflib.
Following is the code m using:
import difflib
from difflib_data import *
with open("s1.txt") as f, open("s2.txt") as g:
flines = f.readlines()
glines = g.readlines()
d = difflib.Differ()
diff = d.compare(flines, glines)
print("\n".join(diff))
Traceback:
from difflib_data import *
ImportError: No module named 'difflib_data'
How to remove this error....thanks
From the following post, it seems it is the example data provided with the PyMOTW tutorial.
I assume the author wants you to copy and paste the source of test data into a new file named difflib_data.py in your working dir.
Copy the following lines into difflib_data.py
text1 = """Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Integereu lacus accumsan arcu fermentum euismod. Donec pulvinar porttitortellus. Aliquam venenatis. Donec facilisis pharetra tortor. In necmauris eget magna consequat convallis. Nam sed sem vitae odiopellentesque interdum. Sed consequat viverra nisl. Suspendisse arcumetus, blandit quis, rhoncus ac, pharetra eget, velit. Maurisurna. Morbi nonummy molestie orci. Praesent nisi elit, fringilla ac,suscipit non, tristique vel, mauris. Curabitur vel lorem id nisl portaadipiscing. Suspendisse eu lectus. In nunc. Duis vulputate tristiqueenim. Donec quis lectus a justo imperdiet tempus."""
text1_lines = text1.splitlines()
text2 = """Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Integereu lacus accumsan arcu fermentum euismod. Donec pulvinar porttitortellus. Aliquam venenatis. Donec facilisis pharetra tortor. In necmauris eget magna consequat convallis. Nam sed sem vitae odiopellentesque interdum. Sed consequat viverra nisl. Suspendisse arcumetus, blandit quis, rhoncus ac, pharetra eget, velit. Maurisurna. Morbi nonummy molestie orci. Praesent nisi elit, fringilla ac,suscipit non, tristique vel, mauris. Curabitur vel lorem id nisl portaadipiscing. Suspendisse eu lectus. In nunc. Duis vulputate tristiqueenim. Donec quis lectus a justo imperdiet tempus."""
text2_lines = text2.splitlines()