How to print 3rd from bottom line in file? - python

I want to read and print the 3rd from last line in date.log. This is specified in the line_from_bottom_line variable.
The log can have any number of lines at any time.
Here is an example of what the log looks like:
192.168.80.231 May 8 2018 18:45:00
192.168.80.231 July 30 2018 09:46:48
192.168.80.231 July 2 2018 14:37:14
If there are only 3 lines in the log, the else line will be printed:
line_number[x1] = [(index,log_time)]
The output will be:
(1, '18:45:00')
Which is not what I want.
If there are 4 or more lines, the line printed will be in the format of:
2018:8:18:45:00
This is what I want.
I think my code below is moving to the bottom line and subtracting 3. So if 4 lines don't exist, it doesn't know
what to print. How can I change it so that the 3rd from bottom line is printed even if there are not 4 or more
lines in the log?
old_time = (line_number[x1][-(line_from_bottom_line)].__str__())
from datetime import datetime, date, time
# this would be the third from last line
line_from_bottom_line = 3
date_order = 2
time_order = 4
year_order = 3
present = datetime.now()
def main():
logfile = open('krinkov.log', 'r+')
line_number = dict()
for index,line in enumerate(logfile,1): # scan lines
if line in ['\n', '\r\n']: # Error Checking: if not enough lines in var .log
print("Not enough lines.")
return
if line:
x1 = line.split()[0] # if line, get IP address
log_day = line.split()[date_order]
log_time = line.split()[time_order] # This will already be in the format of hh:mm:ss
log_year = line.split()[year_order]
if x1 in line_number : # if ip address on line
line_number[x1].append((log_year + ":" + log_day + ":" + log_time))
else:
line_number[x1] = [(index,log_time)]
if x1 in line_number and len(line_number.get(x1,None)) > 1:
# Below is where I am having issues.
# If there are not 4 or more lines in the log, an error occurs.
old_time = (line_number[x1][-line_from_bottom_line])
print(old_time)
# ** get last line number. Print that line number. then subtract 2 from it
# old_time = that new number
else:
print('Nothing')
main()

Problem: Look at where you add new elements to your line_number dictionary:
if x1 in line_number : # if ip address on line
line_number[x1].append((log_year + ":" + log_day + ":" + log_time))
else:
line_number[x1] = [(index,log_time)]
If the dictionary does not contain the IP address yet (i.e. the else part gets executed), you create the IP field with a dictionary containing a list with the element (index,log_time), which is a tuple with two elements.
After that, if the IP address is already contained (the if part gets executed), you only add (log_year + ":" + log_day + ":" + log_time), i.e. the string log_year + ":" + log_day + ":" + log_time. That's because (elem) in Python gets unpacked to elem. If you want to create a tuple containing a single element, you have to write (elem,).
Considering this, it seems likeevery value in your line_number dictionary will look something like this (check this!):
[(1, '18:45:00'), "2018:8:18:45:00", "2018:8:18:45:00", "2018:8:18:45:00" ... ]
Fix: changing [(index,log_time)] in the above excerpt to [(log_year + ":" + log_day + ":" + log_time)] should fix your problem. It's bad coding style though because you're writing the same thing twice. A better solution would be to replace the above code with the following line:
line_number[x1] = line_number.get(x1, []) + [f"{log_year}:{log_day}:{log_time}"]

Related

Python - Need help in printing "with at least 3 spaces between columns and be left-aligned for names and right-aligned for number of occurrence."

I am having a problem with this problem in trying to output with at least 3 spaces between columns and be left-aligned for names and right-aligned for number of occurrence. Please guide me, I am trying to solve this programming problem.
def nameCount(fname1,fname2):
firstFile = open(fname1, 'r')
fContent = firstFile.read()
firstFile.close()
secondFile = open(fname2, 'r')
sContent = secondFile.read()
secondFile.close()
#Split first and last name to the following variables.
for content in fContent:
(first, last) = sContent.split()
countFirstName = 0
countSecondName = 0
if first == content or last == content:
countFirstName += 1
countSecondName += 1
thankYouMessage = 'Thank you for using the nameCount() function'
return thankYouMessage
To print with spaces in between test just us the "\n" which goes to a new line.
print("Hello" + "\n" + "\n" + "\n" + "\n" + "World")
Each "\n" makes it go to a newline each time.
You can try using the %s character for formatting columns

Python print and write output end in ". . ." rather than the complete line

I have tried moving around the strings and variables I am concatenating, using while loops, moved the line and method that I am opening the outfile, etc. No matter what I do my output prints/writes "curl" + my url variable. From there it ends in "..." ex: curl "https://examplesite/...
Does this have something to do with a buffer or slicing problem? Thank you for any and all help. Full code below.
import pandas as pd
# file = open("output.txt","wt")
header_list = ["COLA", "COLB"]
df = pd.read_csv("curl_data.csv", names=header_list)
df_length = len(df)
iterator = 0
with open("output.txt", "w") as file:
for row in df.iterrows():
url = '"https://examplesite'
lic = df.COLA # use %20 instead of spaces
name = df.COLB # use %20 instead of spaces
group = "example group" # use %20 instead of spaces
command = "curl " + url + "license=" + lic + "&name=" + name + "&group=" + group + '"'
print(command)
file.write(str(command))
iterator += 1
if iterator == 1:
break
file.close()
Solved. As Imre Kerr suggested in the comments the problem was with the length of the output.
I changed my for loop to be for i in range(len(df)): this only looped through the dataframe once (as per Barmars suggestion) and changed the references to the columns in my code from df.COLA to df.loc[i, "COLA] so that it did not print the whole dataset everytime. This fixed the problem of the lines being too long and thus I was able to see the full line for each outputted string.

Appending data to a file in Python

The error I am getting is a write() takes exactly one argument (5 given). I was able to get the write to work by making a write statement on each line, but that caused each of the inputs to be written on a new line. What I am trying to do is to have the write happen in a format similar to the table created for the temp file. I am not sure how I would implement the logic to make that happen.
import os
def main ():
temp_file = open('temp.txt', 'a')
temp_file.write('Product Code | Description | Price' + '\n'
'TBL100 | Oak Table | 799.99' + '\n'
'CH23| Cherry Captains Chair | 199.99' + '\n'
'TBL103| WalnutTable |1999.00' + '\n'
'CA5| Chest Five Drawer| 639' + '\n')
another = 'y'
# Add records to the file.
while another == 'y' or another == 'Y':
# Get the coffee record data.
print('Enter the following furniture data:')
code = input('Product code: ')
descr = input('Description: ')
price = float(input('Price: '))
# Append the data to the file.
temp_file.write(code, print('|'), descr, print('|'), str(price) + '\n')
# Determine whether the user wants to add
# another record to the file.
print('Do you want to add another record?')
another = input('Y = yes, anything else = no: ')
# Close the file.
temp_file.close()
print('Data appended to temp_file.')
You should only write one line via one parameter
temp_file.write(f'{code} | {descr} | {price}\n')
In your code, just replace this line
temp_file.write(code, print('|'), descr, print('|'), str(price) + '\n')
by this line
temp_file.write(code + '|' + descr + '|' + str(price) + '\n')
Explanations:
The method write takes one argument, but you provide five in your code. That is the reason of the error you have got. You just have to concatenate your variables to get one string that you will pass to the method.

Read data from file into different arrays in python

I'm creating a simple script for blender and i need a little help with get some data from file i've created before via python.
That file got structure like below:
name first morph
values -1.0000 1.0000
data 35 0.026703 0.115768 -0.068769
data 36 -0.049349 0.015188 -0.029470
data 37 -0.042880 -0.045805 -0.039931
data 38 0.000000 0.115775 -0.068780
name second morph
values -0.6000 1.2000
data 03 0.037259 -0.046251 -0.020062
data 04 -0.010330 -0.046106 -0.019890
…
etc more 2k lines ;p
What i need is to create a loop that read for me those data line by line and put values into three different arrays: names[] values[] and data[] depending on first word of file line.
Manualy it should be like that:
names.append('first morph')
values.append( (-1.0000,1.0000))
data.append((35, 0.026703, 0.115768, -0.068769))
data.append((36, -0.049349, 0.015188, -0.029470))
data.append((37, -0.042880, -0.045805, -0.039931))
data.append((38, 0.000000, 0.115775, -0.068780))
names.append('second morph')
values.append( (-0.6000,1.2000))
…
I dont know why my atempts of creating that kind of 'for line in file:' loop creating more errors than complete data, i dont know why is going out of range, or not getting proper data
Please help how to automate that process instead of writing manualy each line since i already exported needed parameters into a file.
names = []
values = []
data = []
with open('yourfile') as lines:
for line in lines:
first, rest = line.split(' ', 1)
if first == 'name':
names.append(rest)
elif first == 'values':
floats = map(float, rest.split())
values.append(tuple(floats))
elif first == 'data':
int_str, floats_str = rest.split(' ', 1)
floats = map(float, floats_str.split())
data.append( (int(int_str),) + tuple(floats) )
Why do you need it like this? How will you know where the next name starts in your data and values lists?
Here is a simple python "for line in" solution... you can just call processed.py...
fp = open("data1.txt", "r")
data = fp.readlines()
fp1 = open("processed.py", "w")
fp1.write("names = []\nvalues=[]\ndata=[]\n")
for line in data:
s = ""
if "name" in line:
s = "names.append('" + line[5:].strip() + "')"
elif "values" in line:
s = "values.append((" + ", ".join(line[7:].strip().split(" ")) + "))"
elif "data" in line:
s = "data.append((" + ", ".join(line[5:].strip().split(" ")) + "))"
fp1.write(s + "\n");
fp1.close()
fp.close()

Pyparsing 'no such attribute _ParseResults__tokdict' on multi-line inputs

The following code gives me the error 'no such attribute _ParseResuls__tokdict' when run on an input with more than one line.
With single-line files, there is no error. If I comment out either the second or third line shown here, then I don't get that error either, no matter how long the file is.
for line in input:
final = delimitedList(expr).parseString(line)
notid = delimitedList(notid).parseString(line)
dash_tags = ', '.join(format_tree(notid))
print final.lineId + ": " + dash_tags
Does anyone know what's going on here?
EDIT: As suggested, I'm adding the complete code to allow others to reproduce the error.
from pyparsing import *
#first are the basic elements of the expression
#number at the beginning of the line, unique for each line
#top-level category for a sentiment
#semicolon should eventually become a line break
lineId = Word(nums)
topicString = Word(alphanums+'-'+' '+"'")
semicolon = Literal(';')
#call variable early to allow for recursion
#recursive function allowing for a line id at first, then the topic,
#then any subtopics, and so on. Finally, optional semicolon and repeat.
#set results name lineId.lineId here
expr = Forward()
expr << Optional(lineId.setResultsName("lineId")) + topicString.setResultsName("topicString") + \
Optional(nestedExpr(content=delimitedList(expr))).setResultsName("parenthetical") + \
Optional(Suppress(semicolon).setResultsName("semicolon") + expr.setResultsName("subsequentlines"))
notid = Suppress(lineId) + topicString + \
Optional(nestedExpr(content=delimitedList(expr))) + \
Optional(Suppress(semicolon) + expr)
#naming the parenthetical portion for independent reference later
parenthetical = nestedExpr(content=delimitedList(expr))
#open files for read and write
input = open('parserinput.txt')
output = open('parseroutput.txt', 'w')
#defining functions
#takes nested list output of parser grammer and translates it into
#strings suited for the final output
def format_tree(tree):
prefix = ''
for node in tree:
if isinstance(node, basestring):
prefix = node
yield node
else:
for elt in format_tree(node):
yield prefix + '_' + elt
#function for passing tokens from setResultsName
def id_number(tokens):
#print tokens.dump()
lineId = tokens
lineId["lineId"] = lineId.lineId
def topic_string(tokens):
topicString = tokens
topicString["topicString"] = topicString.topicString
def parenthetical_fun(tokens):
parenthetical = tokens
parenthetical["parenthetical"] = parenthetical.parenthetical
#function for splitting line at semicolon and appending numberId
#not currently in use
def split_and_prepend(tokens):
return '\n' + final.lineId
#setting parse actions
lineId.setParseAction(id_number)
topicString.setParseAction(topic_string)
parenthetical.setParseAction(parenthetical)
#reads each line in the input file
#calls the grammar expressed in 'expr' and uses it to read the line and assign names to the tokens for later use
#calls the 'notid' varient to easily return the other elements in the line aside from the lineId
#applies the format tree function and joins the tokens in a comma-separated string
#prints the lineId + the tokens from that line
for line in input:
final = delimitedList(expr).parseString(line)
notid = delimitedList(notid).parseString(line)
dash_tags = ', '.join(format_tree(notid))
print final.lineId + ": " + dash_tags
The input file is a txt document with the following two lines:
1768 dummy; data
1768 dummy data; price
Reassigning of notid breaks the second iteration when used in delimitedList. Your third line destroys the notid expression defined earlier in the code, so it will only work the first iteration. Use a different name for the notid assignment.

Categories