I'm having trouble formatting the strings below. Trying to keep the message centered with the borders, but having a hard time executing it. Below is what output I want and below that is my code I have so far. Note: I need to have a space on the left and right columns of the longest line and I need to utilize the split() func.
+---------------+
| STOP! |
| DANGER AHEAD |
| Drive Safely! |
+---------------+
def border_sign(note):
letter_count = 0
for i in note:
letter_count += 1
return "+-------+\n| {} |\n+-------+\n".format(note)
border_sign("STOP\nDANGER AHEAD\nDrive safely!")
Split the string into separate lines, then center each line. Remember to either print each line immediately within the function, build up a list, or yield each line rather than returning after the first line. You can also determine and use a calculated width rather than a static value.
def border_sign(note):
note = note.splitlines()
m = len(max(note, key=len))
yield ('-'*m).join('++')
for line in note:
yield ("|{:^%d}|" % m).format(line)
yield ('-'*m).join('++')
print(*border_sign("STOP\nDANGER AHEAD\nDrive safely!"), sep='\n')
Quick sample to consider, not production ready code:
def border_sign(note):
rows = note.splitlines()
mlen = len(max(rows, key=len))
print "+" + "-" * (2+mlen) + "+"
for row in rows:
print ("| {:^"+str(mlen)+"} |").format(row)
print "+" + "-" * (2+mlen) + "+"
def border_sign(x):
splitted = x.splitlines()
M = max(map(len,splitted))
horiz = '+-%s-+' % (M*'-')
patiz = '| {0: ^%d} |' % M
print(horiz,*map(patiz.format,splitted), horiz, sep='\n')
border_sign("STOP\nDANGER AHEAD\nDrive safely!")
patiz.format is a function, then can be used in map
Related
How to insert ' # ' for each n index from backward?
ex) n=4
evil = '01234567891234oooooooooooooooo321'
to
stan = '0#1234#5678#9123#4ooo#oooo#oooo#oooo#o321'
i tried using list with for,if statement, got stuck. something shameful like this
a = 1234567891234
b = [ a[-i] for i in range(1,len(a)+1)]
for i in range(len(b)):
c += b[i]
if i%4==0: #stuck
c += ','
c.reverse()
What is the optimum way?
You might use a pattern asserting optional repetitions of 4 characters to the right, and replace that position with #
import re
pattern = r"(?=(?:.{4})*$)"
s = "01234567891234oooooooooooooooo321"
print(re.sub(pattern, "#", s))
Output
0#1234#5678#9123#4ooo#oooo#oooo#oooo#o321#
Python demo
cut the string into chunks (backwards) and then concat them using the seperator
evil = '01234567891234oooooooooooooooo321'
l = 4
sep = '#'
sep.join([evil[max(i-l,0):i] for i in range(len(evil), 0, -l)][::-1])
'0#1234#5678#9123#4ooo#oooo#oooo#oooo#o321'
chunks function as in this answer
def chunks(lst, n):
"""Yield successive n-sized chunks from lst."""
for i in range(0, len(lst), n):
yield lst[i:i + n]
evil = '01234567891234oooooooooooooooo321'
n = 4
stan = "#".join(chunks(evil[::-1], n))[::-1]
print(stan) # Output: 0#1234#5678#9123#4ooo#oooo#oooo#oooo#o321
Input string is reversed ([::-1]), split into chunks, joined by "#" and then reversed back again. (It's possible to skip reverses if you calculate how many characters there will be in the first set of characters)
A naive solution would be using parts of evil string:
evil = '01234567891234oooooooooooooooo321'
n = 4
start = len(evil) % n
insert = '#'
stan = evil[:start] + insert
for i in range(start, len(evil) - n, n):
stan += evil[i:i+n] + insert
stan += evil[-n:]
For this, I would go backwards through your string evil by reversing the string and iterating through it in a for loop. Then I set a count variable to keep track of how many loops it's done, and reset to 0 when it equals 4. All of this looks like the below:
count = 0
for char in evil[::-1]:
if count == 4:
count = 0
count += 1
You can then establish a new empty string (new_str), and append each character of evil to, each time checking if count is 4, and adding a # to the string as well before resetting the count. Full code:
count = 0
new_str = ''
for char in evil[::-1]:
if count == 4:
new_str += '#'
count = 0
count += 1
new_str += char
This will produce the new string reversed, so you need to reverse it again to get the desired result:
new_str = new_str[::-1]
Output:
'123o#oooo#oooo#oooo#ooo4#3219#8765#4321#0'
You can do it like this:
evil = '01234567891234oooooooooooooooo321'
''.join(j if i%4 else f'#{j}' for i, j in enumerate(evil[::-1]))[::-1][:-1]
Output:
'0#1234#5678#9123#4ooo#oooo#oooo#oooo#o321'
An exact method: use divmod to get the reminder and quotient of the string when divided in "blocks" of size 4 then slice.
evil = '01234567891234oooooooooooooooo321'
size = 4
q, r = divmod(len(evil), size)
sep = '#'
stan = f"{evil[:r]}{sep}{sep.join(evil[r+i*size: r+(i+1)*size] for i in range(q))}"
print(stan)
Remark: if the length of the string is a multiple of the block's size the new string will start with sep. Assumed as default behavior since lake of explanation
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)
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)
I want to check a list of numbers in a text file(P1.txt) with the example format below:
68278 63989 64283 65917 66503 68794 68299 64827 65294 68783 68857 68459 66552 63053
66588 68162 67316 66742 65008 64327 65320 68307 65798 65198 67868 67157 63526 63917 ...
I tried to do it with the code that I wrote as below:
with open("P1.txt") as fin, open("P1_c.txt","w") as fout:
for line in fin:
P = line.split()
for i in P:
i=P.split()
if i in range(64600,64799) :
fout.write("|"+str(P)+"+"+" |")
elif i in range(67000,67319) :
fout.write("|"+str(P)+"+"+" |")
elif i in range(67399,67600) :
fout.write("|"+str(P)+"+"+" |")
elif i in range(68000,68699) :
fout.write("|"+str(P)+"+"+" |")
elif i in range(69400,69599) :
fout.write("|"+str(P)+"+"+" |")
else:
fout.write("|"+str(P)+"-"+" |")
I wanted to check whether these numbers are in the ranges that I defined or not. if they are in these ranges, it should print the number and put a "+" afterwards and if not, put a "-" after the number. But I do not know why it does not work?! :)
I even tried to understand what is discussed in this link "Comparing numbers in a text file to a list of numbers in an other textfile"
But did not get anything.
I suggest the following solution: we get all the integers from the file (at once, not a problem if it is not gigantic) and use a helper function that checks whether a number is in any range for a given collection of tuples indicating the range.
>>> def in_ranges(x, range_tuples):
... return any(t[0] <= x < t[1] for t in range_tuples)
>>>
>>> range_tuples = [(64600,64799), (67000,67319), (67399,67600),
... (68000,68699), (69400,69599)]
>>>
>>> with open('testfile') as f:
... for number in map(int, f.read().split()):
... if in_ranges(number, range_tuples):
... sign = '+'
... else:
... sign = '-'
... print '|{}{}|'.format(number, sign)
...
|68278+|
|63989-|
|64283-|
|65917-|
|66503-|
|68794-|
|68299+|
|64827-|
|65294-|
|68783-|
|68857-|
|68459+|
|66552-|
|63053-|
|66588-|
|68162+|
|67316+|
|66742-|
|65008-|
|64327-|
|65320-|
|68307+|
|65798-|
|65198-|
|67868-|
|67157+|
|63526-|
|63917-|
When you read something from a file or sys.stdin, Python threats it as a string object. You should create an int object from string, and the easiest way to do this is to convert the whole list of strings to a list of ints:
P = map(int, line.split())
In this way you apply the function int to every object inside line.split() (which is a list), and put the result (a list of ints) inside P.
P is a list of the numbers in each line, and i takes in each value successively as the loop proceeds, so there's no need to try and split i inside the inner loop. Doing so will bind i to the list [P], and your checks will then try to find that list as an element of the range() expressions.
You should also convert the strings P to integer form before comparing them, per the advice in Peter wood's comment, between the given upper and lower limits.
Reworking your program and without opening the files
testlines = [
'68278 63989 64283 65917 66503 68794 68299 64827 65294 68783 68857 68459 66552 63053',
'66588 68162 67316 66742 65008 64327 65320 68307 65798 65198 67868 67157 63526 63917'
]
ranges = [(64600, 64799), (67000, 67319), (67399, 67600),
(68000, 68699), (69400, 69599)]
for a in testlines:
for num in (int(x) for x in a.split()):
suffix = '-'
for lo, hi in ranges:
if lo <= num < hi:
suffix = '+'
break
print('|' + str(num) + suffix + '|')
Output:
|68278+|
|63989-|
|64283-|
|65917-|
|66503-|
|68794-|
|68299+|
|64827-|
|65294-|
|68783-|
|68857-|
|68459+|
|66552-|
|63053-|
|66588-|
|68162+|
|67316+|
|66742-|
|65008-|
|64327-|
|65320-|
|68307+|
|65798-|
|65198-|
|67868-|
|67157+|
|63526-|
|63917-|
Say we have a function that translates the morse symbols:
. -> -.
- -> ...-
If we apply this function twice, we get e.g:
. -> -. -> ...--.
Given an input string and a number of repetitions, want to know the length of the final string. (Problem 1 from the Flemish Programming Contest VPW, taken from these slides which provide a solution in Haskell).
For the given inputfile
4
. 4
.- 2
-- 2
--... 50
We expect the solution
44
16
20
34028664377246354505728
Since I don't know Haskell, this is my recursive solution in Python that I came up with:
def encode(msg, repetition, morse={'.': '-.', '-': '...-'}):
if isinstance(repetition, str):
repetition = eval(repetition)
while repetition > 0:
newmsg = ''.join(morse[c] for c in msg)
return encode(newmsg, repetition-1)
return len(msg)
def problem1(fn):
with open(fn) as f:
f.next()
for line in f:
print encode(*line.split())
which works for the first three inputs but dies with a memory error for the last input.
How would you rewrite this in a more efficient way?
Edit
Rewrite based on the comments given:
def encode(p, s, repetition):
while repetition > 0:
p,s = p + 3*s, p + s
return encode(p, s, repetition-1)
return p + s
def problem1(fn):
with open(fn) as f:
f.next()
for line in f:
msg, repetition = line.split()
print encode(msg.count('.'), msg.count('-'), int(repetition))
Comments on style and further improvements still welcome
Consider that you don't actually have to output the resulting string, only the length of it. Also consider that the order of '.' and '-' in the string do not affect the final length (e.g. ".- 3" and "-. 3" produce the same final length).
Thus, I would give up on storing the entire string and instead store the number of '.' and the number of '-' as integers.
In your starting string, count the number of dots and dashes. Then apply this:
repetitions = 4
dots = 1
dashes = 0
for i in range(repetitions):
dots, dashes = dots + 3 * dashes, dashes + dots
Think about it why this works.
Per #Hammar (I had the same idea, but he explained it better than I could have ;-):
from sympy import Matrix
t = Matrix([[1,3],[1,1]])
def encode(dots, dashes, reps):
res = matrix([dashes, dots]) * t**reps
return res[0,0] + res[0,1]
you put the count of dots to dashes, and count of dashes to dots in each iteration...
def encode(dots, dashes, repetitions):
while repetitions > 0:
dots, dashes = dots + 3 * dashes, dots + dashes
repetitions -= 1
return dots + dashes
def problem1(fn):
with open(fn) as f:
count = int(next(f))
for i in xrange(count):
line = next(f)
msg, repetition = line.strip().split()
print encode(msg.count('.'), msg.count('-'), int(repetition))