Replace character in list a with character from list b
I have two text files:
clues.txt - contains letter / character pairs:
A#
M*
N%
words.txt - contains a list of the scrambled words:
#+/084&"
#3*#%#+
8%203:
,1$&
!-*%
.#7&33&
#*#71%
&-&641'2
#))85
9&330*
I read the contents of each file in a list using lists:
clues = [line.strip() for line in open("clues.txt", 'r')]
words = [line.strip() for line in open("words.txt", 'r')]
How would I dynamically replace all instances of each character in the list words
with the corresponding character from the list clues
?
So, each instance #
in words
is replaced by A
, each instance *
in words
is replaced by M
, etc.
source to share
You can use str.replace
generating pairs of substrings from each string in the keys and then looping over the reassignment of the string to the updated string value after the replacement:
with open("clues.txt", 'r') as f, open("words.txt", 'r') as f2:
clues = [list(line.rstrip()) for line in f]
for line in f2:
for rep, orig in clues:
line = line.replace(orig, rep)
print(line.rstrip())
Output:
A+/084&"
A3MANA+
8N203:
,1$&
!-MN
.A7&33&
AMA71N
&-&641'2
A))85
9&330M
Or use str.translate :
with open("clues.txt", 'r') as f, open("words.txt", 'r') as f2:
# keys are ord of character to replace,
# values are character to replace with
d = {ord(k): v for v, k in (list(line.rstrip()) for line in f)}
for line in f2:
print(line.translate(d).rstrip())
Output:
A+/084&"
A3MANA+
8N203:
,1$&
!-MN
.A7&33&
AMA71N
&-&641'2
A))85
9&330M
For python2, you need to use string.maketrans
to create the table:
from string import maketrans
with open("clues.txt", 'r') as f, open("words.txt", 'r') as f2:
# separate A -> # ...
a, b = zip(*(list(line.rstrip()) for line in f))
# create table where # maps to A, * -> M and % -> N
tbl = maketrans("".join(b), "".join(a))
for line in f2:
# translate each string using our mapping table
print(line.translate(tbl).rstrip())
Output:
A+/084&"
A3MANA+
8N203:
,1$&
!-MN
.A7&33&
AMA71N
&-&641'2
A))85
9&330M
Python3 requires matching the character of the ord
character to replace with the string you want to replace, in python 2 we do something similar but have to use string.maketrans to create our table that ends as strings '#*%', 'AMN'
.
source to share
The most efficient way to do this is to use string.translate
:
import string
with open('clues.txt', 'r') as cluesf, open('words.txt', 'r') as wordsf:
clues = [line.strip() for line in cluesf]
trans = string.maketrans(''.join([c[1:] for c in clues]), ''.join([c[0] for c in clues]))
words = [line.strip().translate(trans) for line in wordsf]
print(words)
source to share
There are many ways to do this, and there may be various restrictions. As is the size of the word file, regardless of whether the hints are always 2 characters, with the 1st character being replaced and the second character to be replaced. Here is a simple solution you can use.
Instead of reading the words in the list, read it as a string first (assuming a file of a reasonable size) and then replace it with your hints and split it after that. So you can only have replacements once per key. How:
with open('words.txt') as wfd: file_as_string = wfd.read()
for clue in clues: words_str = file_as_string.replace(clue[1], clue[0])
words = [word.strip() for word in file_as_string.split('\n')]
source to share
First convert clues
to display of actual key / value pairs:
clues = [line.strip() for line in open("clues.txt", 'r')]
clues = dict([(k, v) for v, k in clues])
Then we iterate over every character of every word in words
:
for word in words:
for i, c in enumerate(word):
if c in clues:
word[i] = clues[c]
Unfortunately, this is not the most efficient and at worst complexity O^2
.
Update: Improved version:
clues = dict([(k, v) for v, k in map(str.strip, open("clues.txt", "r"))])
with open("words.txt", "r") as f:
for i, c in enumerate(word):
if c in clues:
word[i] = clues[c]
source to share