So I currently have this code to read an accounts.txt file that looks like this:
username1:password1
username2:password2
username3:password3
I then have this (thanks to a member here) read the accounts.txt file and split it at the username and password so I can later print it. When I try to print line 1 with the username and password separate with this code:
with open('accounts.txt') as f:
credentials = [x.strip().split(':') for x in f.readlines()]
for username,password in credentials:
print username[0]
print password[0]
It prints out this:
j
t
a
2
a
3
(These are the three lines I have in the text file, properly split, however it's printing all the lines and only the first letter of each line.)
I've tried a few different methods with no luck. Anyone have an idea on what to do?
Thank you for all your help. It's really appreciated. This is my second day programming and I apologize for such a simple question.
username and password are strings. When you do this to a string, you get the first character in the string:
username[0]
Don't do that. Just print username.
Some further explanation. credentials is a list of lists of strings. It looks like this when you print it out:
[['username1', 'password1'], ['username2', 'password2'], ['username3', 'password3']]
To get one username/password pair, you could do this: print credentials[0]. The result would be this:
['username1', 'password1']
Or if you did print credentials[1], this:
['username2', 'password2']
You can also do a thing called "unpacking," which is what your for loop does. You can do it outside a for loop too:
username, password = credentials[0]
print username, password
The result would be
username1 password1
And again, if you take a string like 'username1' and take a single element of it like so:
username[0]
You get a single letter, u.
First, I'd like to say if this is your second day programming, then you're off to a good start by using the with statement and list comprehensions already!
As the other people already pointed out, since you are using [] indexing with a variable that contains a string, it treats the str as if it were an array, so you get the character at the index you specify.
I thought I'd point out a couple of things:
1) you don't need to use f.readline() to iterate over the file since the file object f is an iterable object (it has the __iter__ method defined which you can check with getattr(f, '__iter__'). So you can do this:
with open('accounts.txt') as f:
for l in f:
try:
(username, password) = l.strip().split(':')
print username
print password
except ValueError:
# ignore ValueError when encountering line that can't be
# split (such as blank lines).
pass
2) You also mentioned you were "curious if there's a way to print only the first line of the file? Or in that case the second, third, etc. by choice?"
The islice(iterable[, start], stop[, step]) function from the itertools package works great for that, for example, to get just the 2nd & 3rd lines (remember indexes start at 0!!!):
from itertools import islice
start = 1; stop = 3
with open('accounts.txt') as f:
for l in islice(f, start, stop):
try:
(username, password) = l.strip().split(':')
print username
print password
except ValueError:
# ignore ValueError when encountering line that can't be
# split (such as blank lines).
pass
Or to get every other line:
from itertools import islice
start = 0; stop = None; step = 2
with open('accounts.txt') as f:
for l in islice(f, start, stop, step):
try:
(username, password) = l.strip().split(':')
print username
print password
except ValueError:
# ignore ValueError when encountering line that can't be
# split (such as blank lines).
pass
Spend time learning itertools (and its recipes!!!); it will simplify your code.
Related
I have a file with lines of data like below I need to pull out the characters at 74-79 and 122-124 some lines will not have any character at 74-79 and I want to skip those lines.
import re
def main():
file=open("CCDATA.TXT","r")
lines =file.readlines()
file.close()
for line in lines:
lines=re.sub(r" +", " ", line)
print(lines)
main()
CF214L214L1671310491084111159 Customer Name 46081 171638440 0000320800000000HCCCIUAW 0612170609170609170300000000003135
CF214L214L1671310491107111509 Customer Name 46144 171639547 0000421200000000DRNRIUAW 0612170613170613170300000000003135
CF214L214L1671380999999900002000007420
CF214L214L1671310491084111159 Customer Name 46081 171638440 0000320800000000DRCSIU 0612170609170609170300000000003135
CF214L214L1671380999999900001000003208
CF214L214L1671510446646410055 Customer Name 46436 171677320 0000027200000272AA 0616170623170623170300000050003001
CF214L214L1671510126566110169 Customer Name 46450 171677321 0000117900001179AA 0616170623170623170300000250003001
CF214L214L1671510063942910172 Customer Name 46413 171677322 0000159300001593AA 0616170623170623170300000150003001
CF214L214L1671510808861010253 Customer Name 46448 171677323 0000298600002986AA 0616170623170623170300000350003001
CF214L214L1671510077309510502 Customer Name 46434 171677324 0000294300002943AA 0616170622170622170300000150003001
CF214L214L1671580999999900029000077728
CF214L214L1671610049631611165 Customer Name 46221 171677648 0000178700000000 0616170619170619170300000000003000
CF214L214L1671610895609911978 Customer Name 46433 171677348 0000011800000118AC 0616170622170622170300000150003041
CF214L214L1671680999999900002000001905
Short answer:
Just take line[74:79] and such as Roelant suggested. Since the lines in your input are always 230 chars long though, there'll never be an IndexError, so you rather need to check if the result is all whitespace with isspace():
field=line[74:79]
<...>
if isspace(field): continue
A more robust approach that would also validate input (check if you're required to do so) is to parse the entire line and use a specific element from the result.
One way is a regex as per Parse a text file and extract a specific column, Tips for reading in a complex file - Python and an example at get the path in a file inside {} by python .
But for your specific format that appears to be an archaic, punchcard-derived one, with column number defining the datum's meaning, the format can probably be more conveniently expressed as a sequence of column numbers associated with field names (you never told us what they mean so I'm using generic names):
fields=[
("id1",(0,39)),
("cname_text":(40,73)),
("num2":(74:79)),
("num3":(96,105)),
#whether to introduce a separate field at [122:125]
# or parse "id4" further after getting it is up to you.
# I'd suggest you follow the official format spec.
("id4":(106,130)),
("num5":(134,168))
]
line_end=230
And parsed like this:
def parse_line(line,fields,end):
result={}
#for whitespace validation
# prev_ecol=0
for fname,(scol,ecol) in format.iteritems():
#optionally validate delimiting whitespace
# assert prev_ecol==scol or isspace(line[prev_ecol,scol])
#lines in the input are always `end' symbols wide, so IndexError will never happen for a valid input
field=line[scol:ecol]
#optionally do conversion and such, this is completely up to you
field=field.rstrip(' ')
if not field: field=None
result[fname]=field
#for whitespace validation
# prev_ecol=ecol
#optionally validate line end
# assert ecol==end or isspace(line[ecol:end])
All that leaves is skip lines where the field is empty:
for line in lines:
data = parse_line(line,fields,line_end)
if any(data[fname] is None for fname in ('num2','id4')): continue
#handle the data
def read_all_lines(filename='CCDATA.TXT'):
with open(filename,"r") as file:
for line in file:
try:
first = line[74:79]
second = line[122:124]
except IndexError:
continue # skip line
else:
do_something_with(first, second)
Edit: Thanks for commenting, apparently it should have been:
for line in file:
first = line[74:79]
second = line[122:124]
if set(first) != set(' ') and set(second) != set(' '):
do_something_with(first, second)
I am trying to write a function that will allow the user to enter a name or phone number, check if it is present in a file, and if it is prints out the entire line in which that element has been found. I have so far:
def searchPlayer():
with open("players.txt") as f:
data = f.readlines()
print "Enter 0 to go back"
nameSearch = str(raw_input("Enter player surname, forname, email, or phone number: "))
if any(nameSearch in s for s in data):
#Finding the element in the list works
#Can't think of a way to print the entire line with the player's information
else:
print nameSearch + " was not found in the database"
The file is formatted like so:
Joe;Bloggs;j.bloggs#anemailaddress.com;0719451625
Sarah;Brown;s.brown#anemailaddress.com;0749154184
So if nameSearch == Joe, the output should be Joe;Bloggs;j.bloggs#anemailaddress.com;0719451625
Any help would be appreciated, thank you
Why not use a loop?
for s in data:
if nameSearch in s:
print s
break
any is looping anyway, from the docs:
def any(iterable):
for element in iterable:
if element:
return True
return False
Seems too complicated, just do
with open("players.txt") as f:
for line in f:
if nameSearch in line:
print line
You can't use any as others have mentioned, but you can use next if you want to keep the more compact code. Instead of:
if any(nameSearch in s for s in data):
you'd use next with a default value:
entry = next((s for s in data if nameSearch in s), None)
if entry is not None:
print entry,
else:
print nameSearch, "was not found in the database"
Note: You might want to use csv.reader or the like to parse here, as otherwise you end up mistaking formatting for data; if a user enters ; you'll blindly return the first record, even though the ; was formatting, not field data. Similarly, a search for Jon would find the first person named Jon or Jonathan or any other name that might exist that begins with Jon.
As #alexis mentioned in a comment, you shouldn't use any() if you want to know which line matched. In this case, you should use a loop instead:
found = False
for s in data:
if nameSearch in s:
print s
found = True
#break # Optional. Put this in if you want to print only the first match.
if not found:
print "{} was not found in the database".format(nameSearch)
If you want to print only the first match, take out the hash sign before break and change if not found: to else:.
I wrote a script for system automation, but I'm getting the error described in the title. My code below is the relevant portion of the script. What is the problem?
import csv
import os
DIR = "C:/Users/Administrator/Desktop/key_list.csv"
def Customer_List(csv):
customer = open(DIR)
for line in customer:
row = []
(row['MEM_ID'],
row['MEM_SQ'],
row['X_AUTH_USER'],
row['X_AUTH_KEY'],
row['X_STORAGE_URL'],
row['ACCESSKEY'],
row['ACCESSKEYID'],
row['ACCESSKEY1'],
row['ACCESSKEYID1'],
row['ACCESSKEY2'],
row['ACCESSKEYID2'])=line.split()
if csv == row['MEM_ID']:
customer.close()
return(row)
else:
print ("Not search for ID")
return([])
id_input = input("Please input the Customer ID(Email): ")
result = Customer_List(id_input)
if result:
print ("iD: " + id['MEM_ID']
For the line
line.split()
What are you splitting on? Looks like a CSV, so try
line.split(',')
Example:
"one,two,three".split() # returns one element ["one,two,three"]
"one,two,three".split(',') # returns three elements ["one", "two", "three"]
As #TigerhawkT3 mentions, it would be better to use the CSV module. Incredibly quick and easy method available here.
The error message is fairly self-explanatory
(a,b,c,d,e) = line.split()
expects line.split() to yield 5 elements, but in your case, it is only yielding 1 element. This could be because the data is not in the format you expect, a rogue malformed line, or maybe an empty line - there's no way to know.
To see what line is causing the issue, you could add some debug statements like this:
if len(line.split()) != 11:
print line
As Martin suggests, you might also be splitting on the wrong delimiter.
Looks like something is wrong with your data, it isn't in the format you are expecting. It could be a new line character or a blank space in the data that is tinkering with your code.
Im stuck on a problem for an assignment, I need to write a program that opens a file on my computer, and scans that file for the first instance of a number. Once it is found it will return
The first number in , filenm is x
otherwise it will say there is no number in filenm.
My code so far is below:
When i run it no matter what it always says theres no number :(
filenm = raw_input("Enter a file name: ")
datain=open(filenm,"r")
try:
c=datain.read(1)
result = []
for line in datain:
c=datain.read(1)
while int(c) >= 0:
c = datain.read(1)
result.append(c)
except:
pass
if len(result) > 0:
print "The first number is",(" ".join(result))+" . "
else:
print "There is no number in" , filenm + "."
That's all you need:
import re
with open("filename") as f:
for line in f:
s=re.search(r'\d+',line)
if s:
print(s.group())
break
open the file;
read it in a loop char-by-char;
check if the char is digit, print whatever you want;
it means there are no numbers in the file, if end-of-file is reached, print "no numbers"
Use <string>.isdigit() method to check if the given string (a single character in your case) is a digit.
I don't recommend mixing iterating through a file
for line in datain:
with using the read method (or any similar one)
c=datain.read(1)
Just stick with one or the other. Personally, I would go with iterating here.
readlines() method returns a list of all the lines in the file. You can then iterate trough the list of characters in each line:
filenm = raw_input("Enter a file name: ")
datain=open(filenm,"r")
try:
result = []
for line in datain.readlines():
print 'line: ' + line
for each in line:
try:
# attempt casting a number to int
int(each)
# if it worked it add it to the result list
result.append(each)
except:
pass
except:
pass
print result
if len(result) > 0:
print "The first number is",(" ".join(result[0]))+". "
else:
print "There is no number in" , filenm + "."
This will only work with the first number character it finds, not sure if you actually need to extract multi digit numbers.
My thoughts:
1) As others noted, don't mask the exception. It would be better to let it be thrown - at least that way you find out what went wrong, if something went wrong.
2) You do want to read the file a line at a time, using for line in file:. The reason for this is that the numbers you want to read are basically "words" (things separated by spaces), and there isn't a built-in way to read the file a word at a time. file.read(1) reads a single byte (i.e. character, for an ASCII file), and then you have to put them together into words yourself, which is tedious. It's much easier to tell Python to split a line into words. At least, I'm assuming here that you're not supposed to pick out the "20" from "spam ham20eggs 10 lobster thermidor".
.readlines() is somewhat redundant; it's a convenience for making a list of the lines in the file - but we don't need that list; we just need the lines one at a time. There is a function defined called .xreadlines() which does that, but it's deprecated - because we can just use for line in file:. Seriously - just keep it simple.
3) int in Python will not return a negative value if the input is non-numeric. It will throw an exception. Your code does not handle that exception properly, because it would break out of the loop. There is no way to tell Python "keep going from where you threw the exception" - and there shouldn't be, because how is the rest of the code supposed to account for what happened?
Actually your code isn't too far off. There are a number of problems. One big one is that the try/except hides errors from you which might have help you figure things out yourself. Another was that you're reading the file with a mixture of a line at a time (and ignoring its contents entirely) as well as a character at a time.
There also seems to be a misunderstand on your part about what the int() function does when given a non-numeric character string, what it does is raise an exception rather than returning something less than 0. While you could enclose a call to it it in a try/except with the except being specifically for ValueError, in this case however it would be easier to just check ahead of time to see if the character is a digit since all you want to do is continue doing that until one that isn't is seen.
So here's one way your code could be revised that would address the above issues:
import string
filenm = raw_input("Enter a file name: ")
datain = open(filenm,"r")
# find first sequence of one or more digits in file
result = []
while True:
c = datain.read(1)
while c in string.digits: # digit?
result.append(c)
c = datain.read(1)
if c == "" or len(result) > 0: # end-of-file or a number has been found
break # get out of loop
if len(result) > 0:
print "The first number is'", "".join(result) + "'."
else:
print "There is no number in'", filenm + "'."
close(datain)
I have a program that logs into a server and issues commands. The results are printed out at the end of the script. The below code shows the script I have created to pass commands through ssh.
import pexpect
ssh_newkey = 'Are you sure you want to continue connecting'
# my ssh command line
p=pexpect.spawn('ssh user#00.00.00.00')
i=p.expect([ssh_newkey,'password:',pexpect.EOF])
if i==0:
print "I say yes"
p.sendline('yes')
i=p.expect([ssh_newkey,'password:',pexpect.EOF])
if i==1:
print "I have entered the password. I will now flip camera through ",
p.sendline("user")
i=p.expect('user#hol-NA:')
p.sendline("cd /opt/ad/bin")
i=p.expect('user#hol-NA:')
p.sendline("./ptzflip")
i=p.expect('user#hol-NA:')
elif i==2:
print "I either got key or connection timeout"
pass
results = p.before # print out the result
print results
The results that the program prints out is:
Value = 1800
Min = 0
Max = 3600
Step = 1
I want to capture the values that are printed out.
In reponse to the questions below. I want to capture eg. 'Value' as a variable and '1800' as its value. I have tried to separate it in a dictionary as mentioned below but I get an error. When I enter:
results_dict = {}
for line in results:
name, val = line.split(' = ')
results_dict[name] = val
I get an error:
Traceback (most recent call last):
File "ptest.py", line 30, in <module>
name, val = line.split(' = ')
ValueError: need more than 1 value to unpack
When I check this code in Python it stores these values as a string. It stores it as:
'/opt/ad/bin$ ./ptzflip\r\nValue = 1800\r\nMin = 0\r\nMax = 3600\r\nStep = 1\r\n'
Can anyone help in this problem. Thanks
Are Value = 1800 etc. the contents of results? And you want to "capture" that?
Do you mean you want to parse those results? Or execute them as python?
If the former you could do something like (untested, unclean, doesn't deal carefully with whitespace):
results_dict = {}
for line in results.splitlines():
try:
name, val = line.split(' = ')
except ValueError:
continue
results_dict[name] = val
This gives you a python dictionary that you can use. If you know that the values are always numbers, you could convert them with int(val) or float(val)... (The try...except ignores lines of the incorrect form; there may be more robust ways to do this, such as if " = " in line)
If you actually want to end up with a variable named Value with the value 1800, you could use eval(results) [or a safer alternative], although this would need to remove lines without the right format first.
do you mean save it to a file?? then try this
open("output.txt","w").write(results)
or when you run the script on the command line:
$ python script.py > output.txt
otherwise, define what you mean by "capture"
After each call to p.expect returns, whatever the child process emitted just before the matched part (any number of lines), and the matched part itself, are accessible as the before and after properties of p -- that's your "capture" for you!
I.e., as the docs put it:
After each call to expect() the before
and after properties will be set to
the text printed by child application.
The before property will contain all
text up to the expected string
pattern. The after string will contain
the text that was matched by the
expected pattern. The match property
is set to the re MatchObject.
The example code in the docs right after this part can be helpful to understand this -- after establishing an FTP session with the interactive ftp client,
child.sendline('ls /pub/OpenBSD/')
child.expect('ftp> ')
print child.before # Print the result of the ls command.
Whenever this happens to me, it's because the string I'm splitting does not have the value I expected. Why not look at it directly?
for line in results:
print line
name, val = line.split(' = ')
results_dict[name] = val
If it were what you think it is, this would work (now in the interpreter):
>>> 'Value = 1800'.split(' = ')
['Value', '1800']