I'm currently using the python linecache module to grab specific lines from a given text document and create a new file with said line. For example, part of the code looks like:
cs = linecache.getline('variables.txt', 7)
cs_1 = open("lo_cs", "w")
cs_1.write(str(cs))
cs_1.close()
The problem is that within variables.txt, line 7 is given by:
variable7 = 3423
for instance. I want the new file, lo_cs, however, to contain only the actual value '3423' and not the entire line of text. Further, I want to insert the whole 'getline' command into an if loop so that if variable7 is left blank, another action is taken. Is there a way to use linecache to check the space following 'variable7 = ' to see if there is anything entered there, and if so, to grab only that particular value or string?
I know (but don't really understand) that bash scripts seem to use '$' as sort of a placeholder for inserting or calling a given file. I think I need to implement something similar to that...
I thought about having instructions in the text file indicating that the value should be specified in the line below -- to avoid selecting out only segments of a line -- but that allows for one to accidentally enter in superfluous breaks, which would mess up all subsequent 'getline' commands, in terms of which line needs to be selected.
Any help in the right direction would be greatly appreciated!
You can use the following method to wrap the functionality you need:
def parseline(l):
sp = l.split('=')
return sp[0], int(sp[1]) if len(sp) > 1 else None
or if you don't need the variable name:
def parseline(l):
sp = l.split('=')
return int(sp[1]) if len(sp) > 1 and sp[1].strip() != '' else None
and then use:
csval = parseline(linecache.getline('variables.txt', 7))
You can later place conditions on csval to see if it's None, and if it is, take another action.
Related
I'm working on a project in my work using purely Python 3:
If I take my scanner, (Because I work in inventory) and anything I scan goes into a text doc, and I scan the location "117" , and then I scan any device in any other location, (the proceeding lines in the text doc "100203") and I run the script and it plugs in '117' in the search on our database and changes each of the devices (whether they were assigned to that location or not) into that location, (Validating those devices are in location '117')
My main question is the 3rd objective down from the Objectives list below that doesn't have "Done" after it.
Objective:
Pull strings from a text document, convert it into a dictionary. = (Text_Dictionary) **Done**
Assign the first var in the dictionary to a separate var. = (First_Line) **Done**
All proceeding var's greater then the first var in the dictionary should be passed into a function individually. = (Proceeding_Lines)
Side note: The code should loop in a fashion that should (.pop) the var from the dictionary/list, But I'm open for other alternatives. (Not mandatory)
What I already have is:
Project.py:
1 import re
2 import os
3 import time
4 import sys
5
6 with open(r"C:\Users\...\text_dictionary.txt") as f:
7 Text_Dictionary = [line.rstrip('\n') for line in
8 open(r"C:\Users\...\text_dictionary.txt")]
9
10 Text_Dict = (Text_Dictionary)
11 First_Line = (Text_Dictionary[0])
12
13 print("The first line is: ", First_Line)
14
15 end = (len(Text_Dictionary) + 1)
16 i = (len(Text_Dictionary))
17
What I have isn't much on the surface, but I have another "*.py" file fill of code that I am going to copy in for the action that I wish to preform on each of the vars in the Text_Dictionary.txt. Lines 15 - 16 was me messing with what I thought might solve this.
In the imported text document, the var's look very close to this (Same length)(All digits):
Text_Dictionary.txt:
117
23000
53455
23454
34534
...
Note: These values will change for each time the code is ran, meaning someone will type/scan in these lines of digits each time.
Explained concept:
Ideally, I would like to have the first line point towards a direction, and the rest of the digits would follow; however, each (Example: '53455') needs to be ran separately then the next in line and (Example: '117') would be where '53455' goes. You could say the first line is static throughout the code, unless otherwise changed inText_Dictionary.txt. '117'is ran in conjunction with each iteration proceeding it.
Background:
This is for inventory management for my office, I am in no way payed for doing this, but it would make my job a heck-of-a-lot easier. Also, I know basic python to get myself around, but this kinda stumped me. Thank you to whoever answers!
I've no clue what you're asking, but I'm going to take a guess. Before I do so, your code was annoying me:
with open("file.txt") as f:
product_ids = [line.strip() for line in f if not line.isspace()]
There. That's all you need. It protects against blank lines in the file and weird invisible spaces too, this way. I decided to leave the data as strings because it probably represents an inventory ID, and in the future that might be upgraded to "53455-b.42454#62dkMlwee".
I'm going to hazard a guess that you want to run different code depending on the number at the top. If so, you can use a dictionary containing functions. You said that you wanted to run code from another file, so this is another_file.py:
__all__ = ["dispatch_whatever"]
dispatch_whatever = {}
def descriptive_name_for_117(product_id):
pass
dispatch_whatever["117"] = descriptive_name_for_117
And back in main_program.py, which is stored in the same directory:
from another_file import dispatch_whatever
for product_id in product_ids[1:]:
dispatch_whatever[product_ids[0]](product_id)
I've found some pieces of answers here and there but I can't figure the exact way to build what I want. Thank you by advance if you can help.
I have multiple text files, all built the same way but with different informations in each one of them. I'd like to loop over each file and return the infos in it line by line. On the other hand I have some booleans which define if one specific line in the file has to be skipped or not. For example: "if boolean1 is true and lineInTheCorrespondingFile = 40, then skip that line, else, read it but skip line 36 and 37 instead".
The thing is I don't know how to proceed for the function knows which file is opened and which line is read and if the it has to skip it or not. Knowing that I need each line to be returned independently at the end of the function.
And here is my code so far:
def locatorsDatas (self):
preset = cmds.optionMenu ("presetMenu", q = 1, v = 1)
rawFile = presetsDir + preset.lower() + ".txt"
with open(rawFile) as file:
file.seek (0)
for lineNum, line in enumerate(file, start = 1):
if lineNum > 8 : # Skip header
locator = eval (line)
locName = locator[0]
xVal = locator[1]
yVal = locator[2]
zVal = locator[3]
locScale = locator[4]
locColor = locator[5]
if locator == "":
break
return (locName, xVal, yVal, zVal, locScale, locColor)
I don't know what values I should pass into the function to make it skip the lines I want, knowing that I can't write it directly into it since each file doesn't break at the same lines.
Oh, and it only return one line of the file instead of each separately.
Hope it's clear and you can help me, thanks again.
I see a number of issues with your code.
To start with, you're always returning the data from line 8 and never any other data. If you have many values you want to extract from the file, you might want to make your function a generator by using a yield statement rather than a return. Then the calling code can access the data with a for loop or pass the generator to list or another function that accepts any iterable.
def locatorsDatas(self):
# ...
lineNum, line in enumerate(file, start=1):
# ...
yield results
If you can't use a generator but need your function to return successive lines, you'll need to save the file iterator (or perhaps the enumerate iterator wrapped around it) somewhere outside the function's scope. That means you won't need to reopen the file every time the function is called. You could do something like:
def __init__(self):
preset = cmds.optionMenu ("presetMenu", q = 1, v = 1)
rawFile = presetsDir + preset.lower() + ".txt"
self.preset_file_enumerator = enumerate(open(rawFile)) # save the iterator on self
def locatorsDatas(self):
try:
lineNum, line = next(self.preset_file_enumerator) # get a value from the iterator
# do your processing
return results
except StopIteration:
# do whatever is appropriate when there's no more data in the file here
raise ValueError("no more data") # such as raising an exception
The next issue I see is how you're processing each line to get the separate pieces of data. You're using eval which is a very bad idea if the data you're processing is even slightly entrusted. That's because eval interprets its argument as Python code. It can do anything, including deleting files from your hard drive! A safer version is available as ast.literal_eval, which only allows the string to contain Python literals (including lists, dictionaries and sets, but not variable lookups, function calls or other more complicated code).
You also have an error check that I don't think will do what you intend. The if locator == "" test is probably placed too late to avoid errors from the earlier lines extracting data from the eval'd line. And the break statement you run will cause the function to exit without returning anything more. If you just want to skip blank lines, you should put the check at the top of the loop and use continue rather than break.
Now finally we can get to the issue you're asking about in the title of the question. If you want to skip certain lines based on various flags, you just need to check those flags as you're looping and do a continue to skip past the lines you don't want to read. I don't entirely understand what you were asking about regarding how the flags are passed, but assuming you can give them as arguments, here's a sketch of how the code could look:
def locatorsDatas(self, skip_40=False, skip_50=True):
# open file, ...
for lineNum, line in enumerate(file, start = 1):
if (not line or
lineNum < 8 or
skip_40 and lineNum == 40 or
skip_50 and lineNum == 50):
continue
# parse the line
yield result
Obviously you should use your own flag names and logic rather than the ones I've made up for my example code. If your logic is more complicated, you might prefer using separate if statements for each flag, rather than packing them all into one lone conditional like I did.
I am trying to scroll trough a result file that one of our process print.
The objective is to look through various blocks and find a specific parameter. I tried to tackle this but can't find an efficient way that would avoid to parse the file multiple times.
This is an example of the output file that I read:
ID:13123
Compound:xyz
... various parameters
RhPhase:abc
ID:543
Compound:lbm
... various parameters
ID:232355
Compound:dfs
... various parameters
RhPhase:cvb
I am looking for a specific ID that has a RhPhase in it, but since the file contains many more entry, I just want that specific ID. It may or may not have an RhPhase in it; if it has one, I get the value.
The only way that I figured out is to actually go through the whole file (which may be hundreds of blocks, to give an idea of the size), and make a list for each ID that has a RhPhase, then in second instance, I scroll through the dictionary, retrieving the value for a specific ID.
This feels so inefficient; I tried to do something different, but got stuck at how you mark the lines while you scroll through them; so I can tell python to read each line->when find the ID that I want continue to read->if you find RhPhase get the value, otherwise stop at the next ID.
I am stuck here:
datafile=open("datafile.txt", "r")
for items in datafile.readline():
if "ID:543" in items:
[read more lines]
[if "RhPhase" in lines:]
[ rhphase=lines ]
[elif ""ID:" in lines ]
[ rhphase=None ]
[ break ]
Once I find the ID; I don't know how to continue to either look for the RhPhase string or find the first ID: string and stop everything (because this means that the ID does not have an associated RhPhase).
This would pass through the file once, and just check for the specific ID, instead of parse the whole thing once and then do a second pass.
Is possible to do so or am I stuck to the double parsing ?
Usually, you solve these kind of things with a simple state machine: You read the lines until you find your id; then you put your reader into a special state that then checks for the parameter you want to extract. In your case, you only have two states: ID not found, and ID found, so a simple boolean is enough:
foundId = False
with open('datafile.txt', 'r') as datafile:
for line in datafile:
if foundId:
if line.startswith('RhPhase'):
print('Found RhPhase for ID 543:')
print(line)
# end reading the file
break
elif line.startswith('ID:'):
print('Error: Found another ID without finding RhPhase first')
break
# if we haven’t found the ID yet, keep looking for it
elif line.startswith('ID:543'):
foundId = True
I'm fairly new to python, but I'm making a script and I want one of the functions to update a variable from another file. It works, but when I exit the script and reload it, the changes aren't there anymore. For example (this isn't my script):
#File: changeFile.txt
number = 0
#File: changerFile.py
def changeNumber():
number += 1
If I retrieve number during that session, it will return 1, but if I exit out and go back in again and retrieve number without calling changeNumber, it returns 0.
How can I get the script to actually save the number edited in changeNumber to changeFile.txt? As I said, I'm fairly new to python, but I've looked just about everywhere on the Internet and couldn't really find an answer that worked.
EDIT: Sorry, I forgot to include that in the actual script, there are other values.
So I want to change number and have it save without deleting the other 10 values stored in that file.
Assuming, as you show, that changeFile.txt has no other content whatever, then just change the function to:
def changeNumber():
global number # will not possibly work w/o this, the way you posted!
number += 1
with open('changeFile.txt', 'w') as f:
f.write('number = {}\n'.format(number))
ADDED: the OP edited the Q to mention (originally omitted!-) the crucial fact that changefile.txt has other lines that need to be preserved as well as the one that needs to be changed.
That, of course, changes everything -- but, Python can cope!-)
Just add import fileinput at the start of this module, and change the last two lines of the above snippet (starting with with) to:
for line in fileinput.input(['changefile.txt'], inplace=True):
if line.startswith('number ');
line = 'number = {}\n'.format(number)'
print line,
This is the Python 2 solution (the OP didn't bother to tell us if using Py2 or Py3, a crucial bit of info -- hey, who cares about making it easy rather than very hard for willing volunteers to help you, right?!-). If Python 3, change the last statement from print line, to
print(line, end='')
to get exactly the same desired effect.
Trying to write a code that searches hash values for specific string's (input by user) and returns the hash if searchquery is present in that line.
Doing this to kind of just learn python a bit more, but it could be a real world application used by an HR department to search a .csv resume database for specific words in each resume.
I'd like this program to look through a .csv file that has three entries per line (id#;applicant name;resume text)
I set it up so that it creates a hash, then created a string for the resume text hash entry, and am trying to use the .find() function to return the entire hash for each instance.
What i'd like is if the word "gpa" is used as a search query and it is found in s['resumetext'] for three applicants(rows in .csv file), it prints the id, name, and resume for every row that has it.(All three applicants)
As it is right now, my program prints the first row in the .csv file(print resume['id'], resume['name'], resume['resumetext']) no matter what the searchquery is, whether it's in the resumetext or not.
lastly, are there better ways to doing this, by searching word documents, pdf's and .txt files in a folder for specific words using python (i've just started reading about the re module and am wondering if this may be the route, rather than putting everything in a .csv file.)
def find_details(id2find):
resumes_f=open("resume_data.csv")
for each_line in resumes_f:
s={}
(s['id'], s['name'], s['resumetext']) = each_line.split(";")
resumetext = str(s['resumetext'])
if resumetext.find(id2find):
return(s)
else:
print "No data matches your search query. Please try again"
searchquery = raw_input("please enter your search term")
resume = find_details(searchquery)
if resume:
print resume['id'], resume['name'], resume['resumetext']
The line
resumetext = str(s['resumetext'])
is redundant, because s['resumetext'] is already a string (since it comes as one of the results from a .split call). So, you can merge this line and the next into
if id2find in s['resumetext']: ...
Your following else is misaligned -- with it placed like that, you'll print the message over and over again. You want to place it after the for loop (and the else isn't needed, though it would work), so I'd suggest:
for each_line in resumes_f:
s = dict(zip('id name resumetext'.split(), each_line.split(";"))
if id2find in s['resumetext']:
return(s)
print "No data matches your search query. Please try again"
I've also shown an alternative way to build dict s, although yours is fine too.
What #Justin Peel said. Also to be more pythonic I would say change
if resumetext.find(id2find) != -1: to if id2find in resumetext:
A few more changes: you might want to lower case the comparison and user input so it matches GPA, gpa, Gpa, etc. You can do this by doing searchquery = raw_input("please enter your search term").lower() and resumetext = s['resumetext'].lower(). You'll note I removed the explicit cast around s['resumetext'] as it's not needed.
One change that I recommend for your code is changing
if resumetext.find(id2find):
to
if resumetext.find(id2find) != -1:
because find() returns -1 if id2find wasn't in resumetext. Otherwise, it returns the index where id2find is first found in resumetext, which could be 0. As #Personman commented, this would give you the false positive because -1 is interpreted as True in Python.
I think that problem has something to do with the fact that find_details() only returns the first entry for which the search string is found in resumetext. It might be good to make find_details() into a generator instead and then you could iterate over it and print the found records out one by one.