replace function not working with list items - python

I am trying to use the replace function to take items from a list and replace the fields below with their corresponding values, but no matter what I do, it only seems to work when it reaches the end of the range (on it's last possible value of i, it successfully replaces a substring, but before that it does not)
for i in range(len(fieldNameList)):
foo = fieldNameList[i]
bar = fieldValueList[i]
msg = msg.replace(foo, bar)
print msg
This is what I get after running that code
<<name>> <<color>> <<age>>
<<name>> <<color>> <<age>>
<<name>> <<color>> 18
I've been stuck on this for way too long. Any advice would be greatly appreciated. Thanks :)
Full code:
def writeDocument():
msgFile = raw_input("Name of file you would like to create or write to?: ")
msgFile = open(msgFile, 'w+')
msg = raw_input("\nType your message here. Indicate replaceable fields by surrounding them with \'<<>>\' Do not use spaces inside your fieldnames.\n\nYou can also create your fieldname list here. Write your first fieldname surrounded by <<>> followed by the value you'd like to assign, then repeat, separating everything by one space. Example: \"<<name>> ryan <<color>> blue\"\n\n")
msg = msg.replace(' ', '\n')
msgFile.write(msg)
msgFile.close()
print "\nDocument written successfully.\n"
def fillDocument():
msgFile = raw_input("Name of file containing the message you'd like to fill?: ")
fieldFile = raw_input("Name of file containing the fieldname list?: ")
msgFile = open(msgFile, 'r+')
fieldFile = open(fieldFile, 'r')
fieldNameList = []
fieldValueList = []
fieldLine = fieldFile.readline()
while fieldLine != '':
fieldNameList.append(fieldLine)
fieldLine = fieldFile.readline()
fieldValueList.append(fieldLine)
fieldLine = fieldFile.readline()
print fieldNameList[0]
print fieldValueList[0]
print fieldNameList[1]
print fieldValueList[1]
msg = msgFile.readline()
for i in range(len(fieldNameList)):
foo = fieldNameList[i]
bar = fieldValueList[i]
msg = msg.replace(foo, bar)
print msg
msgFile.close()
fieldFile.close()
###Program Starts#####--------------------
while True==True:
objective = input("What would you like to do?\n1. Create a new document\n2. Fill in a document with fieldnames\n")
if objective == 1:
writeDocument()
elif objective == 2:
fillDocument()
else:
print "That's not a valid choice."
Message file:
<<name>> <<color>> <<age>>
Fieldname file:
<<name>>
ryan
<<color>>
blue
<<age>>
18

Cause:
This is because all lines except the last line read from the "Fieldname" file contains "\n" characters. So when the program comes to the replacing part fieldNameList , fieldValueList and msg looks like this:
fieldNameList = ['<<name>>\n', '<<color>>\n', '<<age>>\n']
fieldValueList = ['ryan\n', 'blue\n', '18']
msg = '<<name>> <<color>> <<age>>\n'
so the replace() function actually searches for '<<name>>\n','<<color>>\n','<<age>>\n' in msg string and only <<age>> field get replaced.(You must have a "\n" at the end of msg file, otherwise it won't be replaced as well).
Solution:
use rstrip() method when reading lines to strip the newline character at the end.
fieldLine = fieldFile.readline().rstrip()

Related

Combine lines when writing to file in Python?

So I'm trying to write all this info to a .txt file, but due to the names being pulled from a .txt file that goes
Liam
Noah
William
etc...
When I write to a file, it puts the first and last names on separate lines from everything else.
I've looked on StackOverflow for a solution but I couldn't find anything specific enough.
password = input('Enter the Password you would like to use ')
open('names.txt', 'r+')
lines = open("names.txt").readlines()
firstName = lines[0]
words = firstName.split()
firstNameChoice = random.choice(lines)
open('names.txt', 'r+')
lines = open("names.txt").readlines()
lastName = lines[0]
words = lastName.split()
lastNameChoice = random.choice(lines)
def signUp():
randomNumber = str(random.randint(0,10000))
accountFile = open('accounts.txt', 'a')
accountFile.write(firstNameChoice)
accountFile.write(lastNameChoice)
accountFile.write(randomNumber)
accountFile.write('#')
accountFile.write(catchall)
accountFile.write(':')
accountFile.write(password)
accountFile.write('\n')
signUp()
Expectation would be everything printed to one line but that's not the case.
As a quick fix for your problem, you could merge all writing commands in one line:
with open('accounts.txt', 'a') as accountFile: # using a context manager is highly recommended
# with spaces
accountFile.write('{} {} {} # {} : {} \n'.format(
firstNameChoice,
lastNameChoice,
randomNumber,
catchall,
password
)
)
# without spaces
accountFile.write('{}{}{}#{}:{}\n'.format(
firstNameChoice,
lastNameChoice,
randomNumber,
catchall,
password
)
)
If my understanding is right then you want to write everything in one line.
The variables you are writing containing \n while writing into the file.
So you have to replace it with a ' '. Replace this code into your program like:
accountFile.write(firstNameChoice.replace('\n',' '))
accountFile.write(lastNameChoice.replace('\n',' '))
accountFile.write(str(randomNumber).replace('\n',' '))
accountFile.write('#'.replace('\n',' '))
#accountFile.write(catchall)
accountFile.write(':'.replace('\n',' '))
accountFile.write(str(password).replace('\n',' '))
Now it will print like this WilliamWilliam448#:dsada
By the way I dont know what you mean by catchall
The reason it puts it all on a new line is because the strings of your names contains the "\n" on the end because it has an enter to a new line. There is an easy fix for this.
Where you define your first and last name variables add .rstrip() at the end. Like this:
firstNameChoice = random.choice(lines).rstrip()
lastNameChoice = random.choice(lines).rstrip()
def signUp():
randomNumber = str(random.randint(0,10000))
accountFile = open('accounts.txt', 'a')
accountFile.write(f'{firstNameChoice} {lastNameChoice} {randomNumber} # {catchall}: {password} \n')

How do I split a combo list in a large text file?

my problem is that I have a very large database of emails and passwords and I need to send it to a mysql database.
The .txt file format is something like this:
emailnumberone#gmail.com:password1
emailnumbertwo#gmail.com:password2
emailnumberthree#gmail.com:password3
emailnumberfour#gmail.com:password4
emailnumberfive#gmail.com:password5
My idea is to make a loop that takes the line and make it a variable, search the ":" and pick the text before, send it to the db and then the same with the after part of the line. How do I do this?
Short program with some error handling:
Create demo data file:
t = """
emailnumberone#gmail.com:password1
emailnumbertwo#gmail.com:password2
emailnumberthree#gmail.com:password3
emailnumberfour#gmail.com:password4
emailnumberfive#gmail.com:password5
k
: """
with open("f.txt","w") as f: f.write(t)
Parse data / store:
def store_in_db(email,pw):
# replace with db access code
# see http://bobby-tables.com/python
# for parametrized db code in python (or the API of your choice)
print("stored: ", email, pw)
with open("f.txt") as r:
for line in r:
if line.strip(): # weed out empty lines
try:
email, pw = line.split(":",1) # even if : in pw: only split at 1st :
if email.strip() and pw.strip(): # only if both filled
store_in_db(email,pw)
else:
raise ValueError("Something is empty: '"+line+"'")
except Exception as ex:
print("Error: ", line, ex)
Output:
stored: emailnumberone#gmail.com password1
stored: emailnumbertwo#gmail.com password2
stored: emailnumberthree#gmail.com password3
stored: emailnumberfour#gmail.com password4
stored: emailnumberfive#gmail.com password5
Error: k
not enough values to unpack (expected 2, got 1)
Error: : Something is empty: ': '
Edit: According to What characters are allowed in an email address? - a ':' may be part of the first part of an email if quoted.
This would theoretically allow inputs as
`"Cool:Emailadress#google.com:coolish_password"`
which will get errors with this code. See Talip Tolga Sans answer for how to break down the splitting differently to avoid this problem.
This can be done through simple split() method of the strings in python.
>>> a = 'emailnumberone#gmail.com:password1'
>>> b = a.split(':')
>>> b
['emailnumberone#gmail.com', 'password1']
To accomodate #PatrickArtner's complex password fail this can be done:
atLocation = a.find('#')
realSeperator = atLocation + a[atLocation:].find(':')
emailName = a[0:atLocation]
emailDomain = a[atLocation:realSeperator]
email = emailName + emailDomain
password = a[realSeperator + 1:]
print(email, password)
>>> emailnumberone#gmail.com com:plex:PassWord:fail
str.find() returns the first occurrence location of the given character in the given string. Emails can have : in their name field but they can not have #. So first locating the # then locating the : would give you the correct separation locations. After that splitting the string will be piece of cake.
Open file as context manager (with open(...)), You can iterate over the lines with a for loop, then regex match(re Module)(or just split on ":") and use sqlite3 to insert your values to DB.
So the file:
with open("file.txt", "r") as f:
for line in f:
pass #manipulation
Sqlite3 Docs: https://docs.python.org/2/library/sqlite3.html

Pythonic way to traverse etc shadows

I am trying to implement a logic using python :
cat /etc/shadow | awk -F: '($2 == "" ) { print $1 " does not have a password "}'
If the above returns the output for the user i will do
passwd -l <username>
I am trying to implement the above logic using python , but i am not really sure if it is working out in that way; here is my python code:
/etc/shadow looks like
root:*:17709:0:99999:7:::
daemon:*:17709:0:99999:7:::
bin:*:17709:0:99999:7:::
sys:*:17709:0:99999:7:::
sync:*:17709:0:99999:7:::
games:*:17709:0:99999:7:::
man:*:17709:0:99999:7:::
lp:*:17709:0:99999:7:::
mail:*:17709:0:99999:7:::
news:*:17709:0:99999:7:::
uucp:*:17709:0:99999:7:::
proxy:*:17709:0:99999:7:::
www-data:*:17709:0:99999:7:::
backup:*:17709:0:99999:7:::
CODE
with open("/etc/shadow") as file:
for line in file:
line = line.rstrip()
if line[line.find(":")+1:line.find(":")]=="":
print "This is a problem"
elif line[line.find(":")+1:line.find(":")]=="*":
print line[line.find(":")+1:line.find(":")]
else:
print "All Good"
The above code returns "This is a problem" , which isn't right
You can use re to extract desired column:
import re
data = """root:*:17709:0:99999:7:::
daemon:*:17709:0:99999:7:::
bin:*:17709:0:99999:7:::
sys:*:17709:0:99999:7:::
sync:*:17709:0:99999:7:::
games:*:17709:0:99999:7:::
man:*:17709:0:99999:7:::
lp:*:17709:0:99999:7:::
mail:*:17709:0:99999:7:::
news:*:17709:0:99999:7:::
uucp:*:17709:0:99999:7:::
proxy:*:17709:0:99999:7:::
www-data:*:17709:0:99999:7:::
backup:*:17709:0:99999:7:::"""
groups = re.findall('(.*?):(.*?):(.*?):(.*?):(.*?):(.*?):(.*?):(.*?):', data)
if all(g[1].strip() for g in groups):
print('All good')
else:
print('This is a problem')
This prints:
All good
Explanation of this regex here. In the second group (g[1]), you have the shadowed password (*), or empty string.
Try it:
with open("/etc/shadow/") as ff:
for line in ff:
login_name,pwd,remainder=line.split(":",maxsplit=2)
print(login_name,pwd) # change it as you like
Just split your lines on the ":" separator and check the value at the second position (which is at index 1 of course):
data = """
root:*:17709:0:99999:7:::
daemon:*:17709:0:99999:7:::
bin:*:17709:0:99999:7:::
sys:*:17709:0:99999:7:::
sync:*:17709:0:99999:7:::
games:*:17709:0:99999:7:::
man:*:17709:0:99999:7:::
lp:*:17709:0:99999:7:::
mail:*:17709:0:99999:7:::
news:*:17709:0:99999:7:::
uucp:*:17709:0:99999:7:::
proxy:*:17709:0:99999:7:::
www-data:*:17709:0:99999:7:::
backup:*:17709:0:99999:7:::
"""
for line in data.strip().splitlines():
row = [part.strip() for part in line.split(":")]
if row[1] == "":
print("this is a problem")
elif row[1] == "*":
print row[1]
else:
print "all good"

Python- Saving Results to a File and Recalling Them

I'm writing a program in Python that will store Student IDs, names, and D.O.B.s.
The program gives the user the ability to remove, add, or find a student. Here is the code:
students={}
def add_student():
#Lastname, Firstname
name=raw_input("Enter Student's Name")
#ID Number
idnum=raw_input("Enter Student's ID Number")
#D.O.B.
bday=raw_input("Enter Student's Date of Birth")
students[idnum]={'name':name, 'bday':bday}
def delete_student():
idnum=raw_input("delete which student:")
del students[idnum]
def find_student():
print "Find"
menu = {}
menu['1']="Add Student."
menu['2']="Delete Student."
menu['3']="Find Student"
menu['4']="Exit"
while True:
options=menu.keys()
options.sort()
for entry in options:
print entry, menu[entry]
selection=raw_input("Please Select:")
if selection =='1':
add_student()
elif selection == '2':
delete_student()
elif selection == '3':
find_students
elif selection == '4':
break
else:
print "Unknown Option Selected!"
The problem I am having is I cannot figure out how to have the program save any added records to a file when the program ends. It also would need to read back the records when the program restarts.
I keep trying to find tutorials for this sort of thing online, but to no avail. Is this the sort of code I'd want to add?:
f = open("myfile.txt", "a")
I'm new to Python so any help would be appreciated. Thanks so much.
It depends, if you want to actually save python objects, check out Pickle or Shelve, but if you just want to output to a text file, then do the following:
with open('nameOfYourSaveFile', 'w') as saveFile:
#.write() does not automatically add a newline, like print does
saveFile.write(myString + "\n")
Here's an answer that explains the different arguments to open, as in w, w+, a, etc.
As an example, say we have:
with open('nameOfYourSaveFile', 'w') as saveFile:
for i in xrange(10):
saveFile.write(name[i] + str(phoneNumber[i]) + email[i] + "\n")
To read the file back, we do:
names = []
numbers = []
emails = []
with open('nameOfYourSaveFile', 'r') as inFile:
for line in inFile:
#get rid of EOL
line = line.rstrip()
#random example
names.append(line[0])
numbers.append(line[1])
emails.append(line[2])
#Or another approach if we want to simply print each token on a newline
for word in line:
print word
import pickle,os
if os.path.exists("database.dat"):
students = pickle.load(open("database.dat"))
else:
students = {}
... #your program
def save():
pickle.dump(students,open("database.dat","w"))

Use substitution cipher in python to encrypt and decrypt a .txt file and output to a new .txt file

I am able to open the rules file and create a dictionary to use for my encryption. I have to also create a dictionary to use for decrypting text. I assume it's basically the same function with minor changes. The encrypt works fine, but I can't get the decrypt to work. My second problem is that while I encrypted the file I took out all spaces and punctuation. I can't figure out how to get those back in the output file once I run the program. It just prints in a single column. Lastly I have to output this to a .txt file. I am able to create a .txt with a user assigned name, but can't get anything to print on the file.
Here is what I achieved so far.
#import clauses
import string
#function definitions
#encrypt dictionary
def createrulesdictencrypt(openFile):
rulesencrypt1 = {}
for line in openFile:
rulessplit = string.split(string.strip(line))
rulesencrypt1[rulessplit[0]] = rulessplit[1]
return rulesencrypt1
#decrypt dictionary
def createrulesdictdecrypt(openFile):
rulesdecrypt1 = {}
for line in openFile:
rulessplit = string.split(string.strip(line))
rulesdecrypt1[rulessplit[1]] = rulessplit[0]
return rulesdecrypt1
openFile = open('rules.txt', 'r')
rulesencrypt = createrulesdictencrypt(openFile)
rulesdecrypt = createrulesdictdecrypt(openFile)
#print rulesencrypt
#print rulesdecrypt
#function for encrypting file
def encryptfile(openFile2):
for line in openFile2:
for word in line.split():
empty = ''
for char in word:
if char not in string.punctuation:
char=char.lower()
empty = empty+char
if len(empty) == 2:
print rulesencrypt[empty]
empty = ''
if len(empty) == 1:
print rulesencrypt[empty]
#function for decrypting file
def decryptfile(openFile2):
for line in openFile2:
for word in line.split():
empty = ''
for char in word:
if char not in string.punctuation:
char=char.lower()
empty = empty+char
if len(empty) == 2:
print rulesdecrypt[empty]
empty = ''
if len(empty) == 1:
print rulesdecrypt[empty]
#main program
ende = raw_input("To encrypt a file, enter '0':\nTo decrypt a file, enter '1':")
filename = raw_input("Enter the name of the file to be processed:")
outfilename = raw_input("Enter the name of the file to save the result to:")
openFile2 = open(filename, 'r')
outputfile = open(outfilename, 'w')
fileencrypt = encryptfile(openFile2)
filedecrypt = decryptfile(openFile2)
if ende == "0":
print encryptfile(fileencrypt)
if ende == "1":
print decryptfile(filedecrypt)
This is what I am trying to encrypt
Sir Robin: "Oh, you liars!"
Minstrel: [singing] "Bravely taking to his feet, he beat a very brave
retreat. A brave retreat by brave Sir Robin."
Your first problem is that you're not actually writing your encrypted text to a file, instead you're just printing it to sys.stdout. Incidentally, print appends a \n to it's output by default.
You could rewrite your decrypt function as follows:
#function for decrypting file
def decryptfile(openFile2, outfile): # <- CHANGED to add outfile
for line in openFile2:
for word in line.split():
empty = ''
for char in word:
if char not in string.punctuation:
char=char.lower()
empty = empty+char
if len(empty) == 2:
outfile.write(rulesdecrypt[empty]) # <- CHANGED to write to file
empty = ''
if len(empty) == 1:
outfile.write(rulesdecrypt[empty]) # <- CHANGED to write to file
You will then need to invoke the decryptfile function with a file as its second argument. A similar change could be made to the encryptfile function.
With respect to punctuation and whitespace, either encrypt it or just leave it in place. Once you've removed it, there really isn't a good way to replace it.

Categories