Swapping lines in a text - python

How to change this:
fv (x,y,z) begin print x;;; print y ;;; return x + y + z end;
x = fv(2,34,5)
g (x) begin y = x + 45 ;;; return y end;
z = g(23)
r = 53
h (x,y,z,r) begin print x;;; print y ;;; print z;;;print r;;;return x + y + z end;
To this:
def fv (x,y,z) :
print x
print y
return x + y + z
x = fv(2,34,5)
def g (x) :
y = x + 45
return y
z = g(23)
r = 53
def h (x,y,z,r) :
print x
print y
print z
print r
return x + y + z
I'm not asking for a full code or to do my homework, I only need advices and/or samples or a direction how to do this.

Since you're only looking for a starting hint, and this is probably homework...
Do a replace() on the various line-enders (e.g. "begin", ";;;", "end;") converting them to "\n", with possibly a ':' in one of them.
Split the resulting text into lines with .split("\n")
Walk the lines to adjust the line prefixes ("def ", indentation)
Put the lines back together using "\n".join(...)
Write the output text

this could get you started
for line in code:
line = line.replace( "begin", " :\n" + " " * 4 ).replace( ";;;", "\n" + " " * 4 ).replace( "end;", "\n" + " " * 4 )

Look at the sed command line tool, for instance. It's a bit hard to know what tools you're expected/allowed to use ...

Well, for starters you open() the file, use its readlines() method to get it into a list of strings.
From there you could iterate through that list and use a combination of split(";;;") methods or something more complex from the re module on strings.

This might be overkill, but take a look at the Ply parser project. You will have to learn about regular expressions and Backus Naur formatting.
Ply parser

Related

Returning original string with symbols between each character

I'm trying to make my program return the exact same string but with ** between each character. Here's my code.
def separate(st):
total = " "
n = len(st + st[-1])
for i in range(n):
total = str(total) + str(i) + str("**")
return total
x = separate("12abc3")
print(x)
This should return:
1**2**a**b**c**3**
However, I'm getting 0**1**2**3**4**5**6**.
You can join the characters in the string together with "**" as the separator (this works because strings are basically lists in Python). To get the additional "**" at the end, just concatenate.
Here's an example:
def separate(st):
return "**".join(st) + "**"
Sample:
x = separate("12abc3")
print(x) # "1**2**a**b**c**3**"
A note on your posted code:
The reason you get the output you do is because you loop using for i in range(n): so the iteration variable i will be each index in st. Then when you call str(total) + str(i) + str("**"), you cast i to a string, and i was just each index (from 0 to n-1) in st.
To fix that you could iterate over the characters in st directly, like this:
for c in st:
or use the index i to get the character at each position in st, like this:
for i in range(len(st)):
total = total + st[i] + "**"
welcome to StackOverflow!
I will explain part of your code line by line.
for i in range(n) since you are only providing 1 parameter (which is for the stopping point), this will loop starting from n = 0, 1, 2, ... , n-1
total = str(total) + str(i) + str("**") this add i (which is the current number of iteration - 1) and ** to the current total string. Hence, which it is adding those numbers sequentially to the result.
What you should do instead is total = str(total) + st[i] + str("**") so that it will add each character of st one by one
In addition, you could initialize n as n = len(st)

Any simple python code suggestions to add a constant to every individual number in a .txt

so -----2-----3----5----2----3----- would become -----4-----5----7----4----5-----
if the constant was 2 and etc. for every individual line in the text file.
This would involve splitting recognising numbers in between strings and adding a constant to them e.g ---15--- becomes ---17--- not ---35---.
(basically getting a guitar tab and adding a constant to every fret number)
Thanks. Realised this started out vague and confusing so sorry about that.
lets say the file is:
-2--3--5---7--1/n-6---3--5-1---5
and im adding 2, it should become:
-4--5--7---9--3/n-8---5--7-3---7
Change the filename to something relevant and this code will work. Anything below new_string needs to be change for what you need, eg writing to a file.
def addXToAllNum(int: delta, str: line):
values = [x for x in s.split('-') if x.isdigit()]
values = [str(int(x) + delta) for x in values]
return '--'.join(values)
new_string = '' # change this section to save to new file
for line in open('tabfile.txt', 'r'):
new_string += addXToAllNum(delta, line) + '\n'
## general principle
s = '-4--5--7---9--3 -8---5--7-3---7'
addXToAllNum(2, s) #6--7--9--11--10--7--9--5--9
This takes all numbers and increments by the shift regardless of the type of separating characters.
import re
shift = 2
numStr = "---1----9---15---"
print("Input: " + numStr)
resStr = ""
m = re.search("[0-9]+", numStr)
while (m):
resStr += numStr[:m.start(0)]
resStr += str(int(m.group(0)) + shift)
numStr = numStr[m.end(0):]
m = re.search("[0-9]+", numStr)
resStr += numStr
print("Result:" + resStr)
Hi You Can use that to betwine every line in text file add -
rt = ''
f = open('a.txt','r')
app = f.readlines()
for i in app:
rt+=str(i)+'-'
print " ".join(rt.split())
import re
c = 2 # in this example, the increment constant value is 2
with open ('<your file path here>', 'r+') as file:
new_content = re.sub (r'\d+', lambda m : str (int (m.group (0)) + c), file.read ())
file.seek (0)
file.write (new_content)

optimization for faster calculation on python defaultdict

I have such a script;
for b in range(len(xy_alignments.keys())):
print str(b) + " : " + str(len(xy_alignments.keys()))
x = xy_alignments.keys()[b][0]
y = xy_alignments.keys()[b][1]
yx_prob = yx_alignments[(y,x)] / x_phrases[x]
xy_prob = xy_alignments[(x,y)] / y_phrases[y]
line_str = x + "\t" + y + "\t" + str(yx_prob) + "\t" + str(xy_prob) + "\n"
of.write(line_str.encode("utf-8"))
of.close()
xy_alignments, yx_alignments, x_phrases, and y_phrases are
python defaultdict variables which involve millions of keys.
When I run the loop above, it runs damn slowly.
Do python lovers have a suggestion to make it fast?
Thanks,
Here's a more idiomatic version, that should also be faster.
for (x, y), xy_alignment in xy_alignments.iteritems():
yx_prob = yx_alignments[(y, x)] / x_phrases[x]
xy_prob = xy_alignment / y_phrases[y]
of.write(b'%s\t%s\t%s\t%s\n' % (x, y, yx_prob, xy_prob))
This
saves the key() calls which create new lists every time,
saves one dict lookup by using iteritems(),
saves string allocations by using string formatting, and
saves the encode() call because all output is in the ascii range anyway.

Moving object in list

I made a list like this:
mapxy = [[0 for x in range(16)] for x in range(16)]
and I add object from another normal list like this:
for y in range(0, 16):
for x in range(0, 16):
mapxy[x][y] = mapList[o]
Then I want to move one object in the list both down and just change the first index moving it left and right in the list mapxy[x+1][y]
mapxy.pop(f_pos_x)
mapxy.insert(f_pos_x + 1, ["1"])
f_pos_x += 1
(this didn't work quite as I wanted it too, it ended up in-between/created another list inside the first list instead of inserting in the inner list like I wanted it to.)
but also up and down on y: mapxy[x][y+1].
How I want it to look:
Original
mapxy = [[" ", " ", "1"," "][" ", " ", " "," "][" ", " ", " "," "][" ", " ", " "," "]]
When i press right:
mapxy = [[" ", " ", " ","1"][" ", " ", " "," "][" ", " ", " "," "][" ", " ", " "," "]]
And when I press down:
mapxy = [[" ", " ", " "," "][" ", " ", " ","1"][" ", " ", " "," "][" ", " ", " "," "]]
mapxy is a list of lists (with apparently all "cells" initialized to the single item mapList[o], which is slightly strange). So pop and insert into it would remove and respectively add a whole list at a time, not a single item.
You say you want to "move" an item but not what should take its place. If you just want to copy the item, it's clearly just:
map[x+1][y] = map[x][y]
but if the previous map[x][y] must be filled w/something else you'll then have to assign to that, too, of course. Exactly the same for "moving" along y rather than along x.
Use a dictionary with a tuple as key:
map = {}
for x in range(16):
for y in range(16):
map[x, y] = 0
Actually, you could avoid the initialization and check whether an element is set or use a default value. Concerning this default value, consider None, too. With this dict, you can "move" elements easily:
map[1, 2] = 42
v = map.pop((1, 2))
map[3, 4] = v
Here is the full script that I think does what you want. But before I just paste it and run away, there two things worth saying. 1. You need to swap items in-place. 2. You need to cater for the out of range index errors.
To first i envisaged using a deque of deques with maxlen field set. deque is available from the collections library. So to shift left, you pop at the right and insert at the left and to shift to the right you pop at the left and append at the right. But then I had another idea.
You stick with the list of lists, you swap items in-place and avoid out of range errors by the new computed index is within the set of non-negative integers modulo length of the list containing the item.
Enough talking. To swap in-place in python, given:
x = [8, 21, 100, 9, 5]
You do:
x[2], x[3] = x[3], x[2]
Resulting in:
x = [8, 21, 9, 100, 5]
The script below keeps track of two indices, x corresponds to the index of the item, the string, being moved left and right and y corresponds to the index of the inner list item containing the the item to be moved left and right (the inner list itself is moved up and down). By index i mean position. So x points to the string, y points to the list.
To move up and down the containing list, you only need to know the index of the list to move, y. To move left and right the item (the string), you need to know both the containing list index y and the item index x.
#!/usr/bin/python
from collections import deque
def move_dowm(data, y):
old_y = y
y = (y + 1) % len(data)
data[old_y], data[y] = data[y], data[old_y]
return y
def move_up(data, y):
old_y = y
y = (y - 1) % len(data)
data[old_y], data[y] = data[y], data[old_y]
return y
def move_right(data, x, y):
old_x = x
x = (x + 1) % len(data[y])
data[y][old_x], data[y][x] = data[y][x], data[y][old_x]
return x
def move_left(data, x, y):
old_x = x
x = (x - 1) % len(data[y])
data[y][old_x], data[y][x] = data[y][x], data[y][old_x]
return x
if __name__ == '__main__':
dataset = [
[' ', ' ', ' ', ' '],
['1', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
[' ', ' ', ' ', ' '],
]
x, y = 0, 1
print dataset
print '-' * 90
y = move_up(dataset, y)
print dataset
print '-' * 90
y = move_dowm(dataset, y)
print dataset
print '-' * 90
x = move_left(dataset, x, y)
print dataset
print '-' * 90
x = move_right(dataset, x, y)
print dataset
print

How to join correctly join words that trails or heads of dashes? - python

I have a list of strings that contains tokens that ends or starts with - I need to join them up such that the words with dashes join up into the correct tokens, e.g.
[in]:
x = "ko- zo- fond- w- a (* nga- bantawana )."
y = "ngi -leth- el a -unfundi"
z = "ba- ya -gula buye incdai- fv -buye"
[out]:
kozofondwa (* ngabantawana ).
ngilethel aunfundi
bayagula buye incdaifvbuye
I've been doing it as such, it's real ugly and inelegant especially when i need to call the function twice. Is there other way to achieve the same output? maybe with regex or something?
x = "ko- zo- fond- w- a (* nga- bantawana )."
y = "ngi -leth- el a -unfundi"
z = "ba- ya -gula buye incdai- fv -buye"
def join_morph(text):
tempstr = ""
outstr = []
for i in text.split():
if i.startswith('-'):
outstr[len(outstr)-1]+=i
elif i.endswith('-'):
tempstr+=i
else:
tempstr+=i
outstr.append(tempstr)
tempstr = ""
return " ".join(outstr)
# There is a problem because of the ordering of
# the if-else, it can only handle head or
# trailing dashes, not both
a = join_morph(x)
print a
a = join_morph(x).replace('-','')
print a
a = join_morph(join_morph(y)).replace('-','')
print a
a = join_morph(join_morph(z)).replace('-','')
print a
x = "ko- zo- fond- w- a (* nga- bantawana )." #or any other input
x = x.replace("- ", "").replace(" -", "")
It will remove all occurrences of "- " and " -" from the input effectively transforming strings as you need it.
maybe:
import re
re.sub( ' *- *', '', txt )
edit: if you know that there will always be exactly one space before or after the dash, then go with the replace solution, otherwise if you expect to have strings like high-rise( no space before or after dash), or high -rise (more than one space) or high - rise (one space on both sides), then the regular expression may fit better.

Categories