AutocompleteInput for all words in string (Bokeh) - python

I've made an interactive Bokeh plot with an AutocompleteInput widget (link here - the widget is the name input on the left hand side).
The auto completion currently only works with exact matches of the entire string.
Is there a way for it to work with any word in the string, with words being deliminated by spaces?
The code used for the widget is below, and an abridged list that makes up the completions.
name_list = ['Takehiro Tomiyasu', 'Marco Benassi', 'Leandro Barreiro Martins']
name = AutocompleteInput(title='Highlighted player name:', value='Takehiro Tomiyasu', completions=name_list,
restrict=True, case_sensitive=False)
Many thanks.

Related

Renpy python variable text color

I started making a novel and learn renpy really recently, and I came across a difficulty that I couldn't find the solution. I put an input for the user to define the name of the protagonist, but when I declare the character, the color that I designated to appear in the text box is not working.
Here a piece of my code:
python:
sn = ""
define luca = Character(" Luca Kaneshiro", color="#ffffff")
define sn = Character("%(sn)s", color="#ffffff")
label start:
call askname
luca "Hey %(sn)s."
sn "Hi, Luca!"
label askname:
$ sn = renpy.input("What's my name?", length=32)
here's how the text in displayed
I was expecting it to be displayed in white color, but instead it was displayed in yellow, the collor that I defined for gui.accent_color. Is there any solution for that? A way to turn the text in the sn variable into a normal text or something like this?
According to Renpy's documentation on Character, you need to attached a who_style arguments, specifically who_color in this case:
define sn = Character("%(sn)s", who_color="#ffffff")
Also, unrelated but renpy doc uses square bracket for string/text interpolation instead, so in case the above doesn't work, try the following:
define sn = Character("[sn]", who_color="#ffffff")

Substring with multiple instances of the same character

So I am using a Magtek USB reader that will read card information,
As of right now I can swipe a card and I get a long string of information that goes into a Tkinter Entry textbox that looks like this
%B8954756016548963^LAST/FIRST INITIAL^180912345678912345678901234?;8954756016548963=180912345678912345678901234?
All of the data has been randomized, but that's the format
I've got a tkinter button (it gets the text from the entry box in the format I included above and runs this)
def printCD(self):
print(self.carddata.get())
self.card_data_get = self.carddata.get()
self.creditnumber =
self.card_data_get[self.card_data_get.find("B")+1:
self.card_data_get.find("^")]
print(self.creditnumber)
print(self.card_data_get.count("^"))
This outputs:
%B8954756016548963^LAST/FIRST INITIAL^180912345678912345678901234?;8954756016548963=180912345678912345678901234?
8954756016548963
This yields no issues, but if I wanted to get the next two variables firstname, and lastname
I would need to reuse self.variable.find("^") because in the format it's used before LAST and after INITIAL
So far when I've tried to do this it hasn't been able to reuse "^"
Any takers on how I can split that string of text up into individual variables:
Card Number
First Name
Last Name
Expiration Date
Regex will work for this. I didn't capture everything because you didn't detail what's what but here's an example of capturing the name:
import re
data = "%B8954756016548963^LAST/FIRST INITIAL^180912345678912345678901234?;8954756016548963=180912345678912345678901234?"
matches = re.search(r"\^(?P<name>.+)\^", data)
print(matches.group('name'))
# LAST/FIRST INITIAL
If you aren't familiar with regex, here's a way of testing pattern matching: https://regex101.com/r/lAARCP/1 and an intro tutorial: https://regexone.com/
But basically, I'm searching for (one or more of anything with .+ between two carrots, ^).
Actually, since you mentioned having first and last separate, you'd use this regex:
\^(?P<last>.+)/(?P<first>.+)\^
This question may also interest you regarding finding something twice: Finding multiple occurrences of a string within a string in Python
If you find regex difficult you can divide the problem into smaller pieces and attack one at a time:
data = '%B8954756016548963^LAST/FIRST INITIAL^180912345678912345678901234?;8954756016548963=180912345678912345678901234?'
pieces = data.split('^') # Divide in pieces, one of which contains name
for piece in pieces:
if '/' in piece:
last, the_rest = piece.split('/')
first, initial = the_rest.split()
print('Name:', first, initial, last)
elif piece.startswith('%B'):
print('Card no:', piece[2:])

How can I accurately set the new cursor positions after text replacements have been made

I am trying to adapt a plugin for automated text replacement in a Sublime Text 3 Plugin. What I want it to do is paste in text from the clipboard and make some automatic text substitutions
import sublime
import sublime_plugin
import re
class PasteAndEscapeCommand(sublime_plugin.TextCommand):
def run(self, edit):
# Position of cursor for all selections
before_selections = [sel for sel in self.view.sel()]
# Paste from clipboard
self.view.run_command('paste')
# Postion of cursor for all selections after paste
after_selections = [sel for sel in self.view.sel()]
# Define a new region based on pre and post paste cursor positions
new_selections = list()
delta = 0
for before, after in zip(before_selections, after_selections):
new = sublime.Region(before.begin() + delta, after.end())
delta = after.end() - before.end()
new_selections.append(new)
# Clear any existing selections
self.view.sel().clear()
# Select the saved region
self.view.sel().add_all(new_selections)
# Replace text accordingly
for region in self.view.sel():
# Get the text from the selected region
text = self.view.substr(region)
# Make the required edits on the text
text = text.replace("\\","\\\\")
text = text.replace("_","\\_")
text = text.replace("*","\\*")
# Paste the text back to the saved region
self.view.replace(edit, region, text)
# Clear selections and set cursor position
self.view.sel().clear()
self.view.sel().add_all(after_selections)
This works for the most part except I need to get the new region for the edited text. The cursor will be placed to the location of the end of the pasted text. However since I am making replacements which always make the text larger the final position will be inaccurate.
I know very little about Python for Sublime and like most others this is my first plugin.
How do I set the cursor position to account for the size changes in the text. I know I need to do something with the after_selections list as I am not sure how to create new regions as they were created from selections which are cleared in an earlier step.
I feel that I am getting close with
# Add the updated region to the selection
self.view.sel().subtract(region)
self.view.sel().add(sublime.Region(region.begin()+len(text)))
This, for some yet unknown to me reason, places the cursor at the beginning and end of the replaced text. A guess would be that I am removing the regions one by one but forgetting some "initial" region that also exists.
Note
I am pretty sure the double loop in the code in the question here is redundant. but that is outside the scope of the question.
I think your own answer to your question is a good one and probably the way I would go if I was to do something like this in this manner.
In particular, since the plugin is modifying the text on the fly and making it longer, the first way that immediately presents itself as a solution other than what your own answer is doing would be to track the length change of the text after the replacements so you can adjust the selections accordingly.
Since I can't really provide a better answer to your question than the one you already came up with, here's an alternative solution to this instead:
import sublime
import sublime_plugin
class PasteAndEscapeCommand(sublime_plugin.TextCommand):
def run(self, edit):
org_text = sublime.get_clipboard()
text = org_text.replace("\\","\\\\")
text = text.replace("_","\\_")
text = text.replace("*","\\*")
sublime.set_clipboard(text)
self.view.run_command("paste")
sublime.set_clipboard(org_text)
This modifies the text on the clipboard to be quoted the way you want it to be quoted so that it can just use the built in paste command to perform the paste.
The last part puts the original clipboard text back on the clipboard, which for your purposes may or may not be needed.
So, one approach for this would be to make new regions as the replaced text is created using their respective lengths as starting positions. Then once the loop is complete clear all existing selections and set the new one we created in the replacement loop.
# Replace text accordingly
new_replacedselections = list()
for region in self.view.sel():
# Get the text from the selected region
text = self.view.substr(region)
# Make the required edits on the text
text = text.replace("\\","\\\\") # Double up slashes
text = text.replace("*","\\*") # Escape *
text = text.replace("_","\\_") # Escape _
# Paste the text back to the saved region
self.view.replace(edit, region, text)
# Add the updated region to the collection
new_replacedselections.append(sublime.Region(region.begin()+len(text)))
# Set the selection positions after the new insertions.
self.view.sel().clear()
self.view.sel().add_all(new_replacedselections)

how to regain the original font properties and its associated properties like bold, italics using python-docx while text replacement

I am using python-docx for a automation tool. I have a issue like once after I run the code for replacement of certain words in one list with corresponding in another list it is removing all the properties (like font size, font name, part of a text in bold or italics, bookmarks in the paragraphs or table) of the text in the paragraph and table and its coming with a plain text in "Calibri" with a font size of '12'.
The code that I used is:
wrongWord = "xyz"
correctWord = "abcd"
def iter_block_items(parent):
if isinstance(parent, _Document):
parent_elm = parent.element.body
elif isinstance(parent, _Cell):
parent_elm = parent._tc
else:
raise ValueError("something's not right")
for child in parent_elm.iterchildren():
if isinstance(child, CT_P):
yield Paragraph(child, parent)
elif isinstance(child, CT_Tbl):
yield Table(child, parent)
document = Document(r"F:\python\documentSample.docx")
for block in iter_block_items(document):
if isinstance(block, Paragraph):
if wrongWord in block.text:
block.text = block.text.replace(wrongWord, correctWord)
else:
for row in block.rows:
for cell in row.cells:
if wrongWord in cell.text:
cell.text = cell.text.replace(wrongWord, correctWord)
document.save(r"F:\python\documentSampleAfterChanges.docx")
Could you help me to get the same font size, font name and other associated properties to be copied from the original file after the text replacement.
Search and replace is a hard problem in the general case, which is the main reason that feature hasn't been added yet.
What's happening here is that assigning to the .text attribute on the cell is removing all the existing runs and the font-related attributes are removed with those runs.
Font information (e.g. bold, italic, typeface, size) is stored at the run level (a paragraph is composed of zero or more runs). Assigning to the .text attribute removes all the runs and replaces them with a single new run containing the assigned text.
So the challenge is to find the text within the multiple runs somewhere, and preserve as much of the font formatting settings as possible.
This is a hard problem because Word breaks paragraph text into separate runs for many reasons, and runs tend to proliferate. There's no guarantee at all that your search term will be completely enclosed in a single run or start at a run boundary. So perhaps you start to see the challenge of a general-case solution.
One thing you can do that might work in your case is something like this:
# ---replace text of first run with new cell value---
runs = table_cell.paragraphs[0].runs
runs[0].text = replacement_text
# ---delete all remaining runs---
for run in runs[1:]:
r = run._element
r.getparent().remove(r)
Basically this replaces the text of the first run and deletes any remaining runs. Since the first run often contains the formatting you want, this can often work. If the first word is formatted differently though, say bold, then all the replacement text will be bold too. You'll have to see how this approach works in your specific case.

Sublime Text 2 plugin: capture the selected text

I am trying to write my first ST2 plugin (I'm also new to Python). What I want to do is capture the currently selected text. This is what I have thus far. I thought this would save all the selected text into the text variable but it looks like I'm only capturing the beginning and ending indices of the selection. Thus, if I select the first character in the buffer, my plugin callback prints "01". What I want is the text between index 0 and index 1.
import sublime, sublime_plugin
class CopyOnSelectListener(sublime_plugin.EventListener):
def on_selection_modified(self, view):
selections = view.sel()
text = ""
for s in selections:
text += str(s.begin())
if not s.empty():
text += str(s.end())
print(text)
The ST2 API reference is here. view.sel() returns a RegionSet, an object containing the Region of each selection. Region.a and Region.b are the integers referring to the beginning and ending, respectively, of the region. So, if your view contains
This is some text.
and you have selected text, Region.a would be 13 and Region.b would be 17. To actually get the contents of a Region, you need to use view.substr(region). The following code will print the contents of each selection to the console:
import sublime_plugin
class PrintSelectionTextCommand(sublime_plugin.TextCommand):
def run(self, edit):
view = self.view
for region in view.sel():
print(view.substr(region))
You can run it by opening the console with Ctrl`, making one or more selections in the open file, then running
view.run_command("print_selection_text")
from the console (assuming you've saved it as Packages/User/print_selection_text.py).

Categories