Input on multiple lines - python-3.x

I try to write a short program which takes multiple pdf files and merges them into one file. The whole thing should operate over a command line.
I use the argparse-package from python. The program works when I call it and give exactly two files to merge. But I want it to be more flexible. Concrete, what I want to do is calling the program, give the first file and hit enter. Then it should ask for the second file: I give it and hit enter, and so on until I hit enter without inserting any file. Like this, the program should know that all files are given.
Every time I hit enter, the program executes and I don't have any chance to do anything else. I searched for a workaround but didn't find any.

You can use input:
files = []
file = input("Your file: ").strip()
while file:
files.append(file)
file = input("Your file: ").strip()
print(f"Files to process: {files}")

Related

How to make it so my code remembers what is has written in a text file?

Hello python newbie here.
I have code that prints names into a text file. It takes the names from a website. And on that website, there may be multiple same names. It filters them perfectly without an issue into one name by looking if the name has already written in the text file. But when I run the code again it ignores the names that are already in the text file. It just filters the names it has written on the same session. So my question is how do I make it remember what it has written.
image of the text file
kaupan_nimi = driver.find_element_by_xpath("//span[#class='store_name']").text
with open("mainostetut_yritykset.txt", "r+") as tiedosto:
if kaupan_nimi in tiedosto:
print("\033[33mNimi oli jo tiedostossa\033[0m")
else:
print("\033[32mUusi asiakas vahvistettu!\033[0m")
#Kirjoittaa tekstitiedostoon yrityksen nimen
tiedosto.seek(0)
data = tiedosto.read(100)
if len(data) > 0:
tiedosto.write("\n")
tiedosto.write(kaupan_nimi)
There is the code that I think is the problem. Please correct me if I am wrong.
There are two main issues with your current code.
The first is that you are likely only going to be able to detect duplicated names if they are back to back. That is, if the prior name that you're seeing again was the very last thing written into the file. That's because all the lines in the file except the last one will have newlines at the end of them, but your names do not have newlines. You're currently looking for an exact match for a name as a line, so you'll only ever have a chance to see that with the last line, since it doesn't have a newline yet. If the list of names you are processing is sorted, the duplicates will naturally be clumped together, but if you add in some other list of names later, it probably won't pick up exactly where the last list left off.
The second issue in your code is that it will tend to clobber anything that gets written more than 100 characters into the file, starting every new line at that point, once it starts filling up a bit.
Lets look at the different parts of your code:
if kaupan_nimi in tiedosto:
This is your duplicate check, it treats the file as an iterator and reads each line, checking if kaupan_nimi is an exact match to any of them. This will always fail for most of the lines in the file because they'll end with "\n" while kaupan_nimi does not.
I would suggest instead reading the file only once per batch of names, and keeping a set of names in your program's memory that you can check your names-to-be-added against. This will be more efficient, and won't require repeated reading from the disk, or run into newline issues.
tiedosto.seek(0)
data = tiedosto.read(100)
if len(data) > 0:
tiedosto.write("\n")
This code appears to be checking if the file is empty or not. However, it always leaves the file position just past character 100 (or at the end of the file if there were fewer than 100 characters in it so far). You can probably fit several names in that first 100 characters, but after that, you'll always end up with the names starting at index 100 and going on from there. This means you'll get names written on top of each other.
If you take my earlier advice and keep a set of known names, you could check that set to see if it is empty or not. This doesn't require doing anything to the file, so the position you're operating on it can remain at the end all of the time. Another option is to always end every line in the file with a newline so that you don't need to worry about whether to prepend a newline only if the file isn't empty, since you know that at the end of the file you'll always be writing a fresh line. Just follow each name with a newline and you'll always be doing the right thing.
Here's how I'd put things together:
# if possible, do this only once, at the start of the website reading procedure:
with open("mainostetut_yritykset.txt", "r+") as tiedosto:
known_names = set(name.strip() for name in tiedosto) # names already in the file
# do the next parts in some kind of loop over the names you want to add
for name in something():
if name in known_names: # duplicate found
print("\033[33mNimi oli jo tiedostossa\033[0m")
else: # not a duplicate
print("\033[32mUusi asiakas vahvistettu!\033[0m")
tiedosto.write(kaupan_nimi) # write out the name
tiedosto.write("\n") # and always add a newline afterwards
# alternatively, if you can't have a trailing newline at the end, use:
# if known_names:
# tiedosto.write("\n")
# tiedosto.write(kaupan_nimi)
known_names.add(kaupan_nimi) # update the set of names

Unsure how to resolve this overwriting error

I have a function that prompts the user to enter their firstname, Surname, Password and id.
What I realised is that every time I run this function it just overwrites my previous values for these 4 variables. What I want to achieve is to be able to run this function and then write the details to a text file and permanently save it and then be able to add another user's details and upload it. Currently when I restart the program and run my student registeration function it's just overwriting my previous variables. Perhaps I shouldn't store my data in variables? Any tips on how to resolve this?
f = open("studentlogindetails.txt", "a+")
f.write("\n" + firstname + " " + surname + " " + universitypassword + " " + universityid)
f.close()
The a+ mode is used to open a file to be read and appended to. Because it is intended to be read, the cursor is placed at the very beginning of the file under the assumption that you are going to immediately try to read from the file. When you try to write, the data written starts wherever the cursor is. You want to place the cursor at the end of the file before you write.
If you don't need to read information and only write, you can use the a mode instead, which opens the file for appending information and places the cursor at the end of the file.
Alternatively, you can manually move the cursor to the end of the file with the f.seek method.
The documentation states:
fileObject.seek(offset[, whence])
offset − This is the position of the read/write pointer within the file.
whence − This is optional and defaults to 0 which means absolute file positioning, other values are 1 which means seek relative to the current position and 2 means seek relative to the file's end.
So, if you want to keep using the a+ mode, you have to remember to use f.seek(0, 2) to place the cursor 0 bytes from the end of the file before writing.
The available file-open modes and their use can be seen below:
r: Opens the file in read-only mode. Starts reading from the beginning of the file and is the default mode for the open() function.
rb: Opens the file as read-only in binary format. Places the cursor at the start of the file.
r+: Opens a file for reading and writing. Places the cursor at the beginning of the file.
w: Opens in write-only mode. Places the cursor at the beginning of the file. This will overwrite any existing file with the same name. It will create a new file if one with the same name doesn't exist.
wb: Same behavior as w, except the file is opened in binary mode.
w+: Opens a file for writing and reading. Replaces all content and creates the file if it doesn't exist. This mode is used when you need to write to an empty-file and potentially read from it later in your code (before closing).
wb+: Same behavior as w+ except the file is in binary mode.
a: Opens a file for appending new information to it. The cursor is placed at the end of the file. A new file is created if one with the same name doesn't exist.
ab: Same behavior as a except the file is in binary mode.
a+: Opens a file for both appending and reading. The cursor is placed at the beginning of the file.
ab+: Same as a+ except the file is in binary mode.
Information for the modes was pulled and edited from here.
You should use the with keyword and write your data, you can pass the append argument as well.
with open("studentlogindetails.txt", "a") as f:
# Using f-strings
f.write(f"{firstname} {surname} {universitypassword} {universityid}")
Using with ensures all resources are cleaned up even if an error occurs.
Note: If this is just a project you're playing around with to learn how to write text files, then you're probably fine, however, if this is going to be used in production, it's best you use a proper database.
It looks like your writing some user data at a University, you can use the ID that is given to every student and employee as the primary key.
Also, don't store passwords in plain text, and don't implements your own hashing algorithm. Many robust solutions exist.

Writing to a text file in seperate lines

I am creating a program, which at the end of all the inputs, I write to a text file and it comes up as one big line. Other than going into my text file and manually changing it to multiple lines, how do you write to a python text file in separate lines?
Eta:
Line one that holds one piece of inputted information
Line two that holds another piece of inputted information
Line three that holds a final piece of inputted information
I've tried writing twice to a file before closing it, but it returns an error saying it expected 1 argument and received more.
You should post at least a failed attempt that we can fix; but, due to the simplistic nature of the problem, I'll just give a quick answer anyway.
Steps:
Open the file in write ('w') mode (note that this blanks the file)
Write a line
Write a new-line ('\n'). Note that this step can be combined with the previous
Repeat steps 2 and 3 for all your lines
Close the file.
So, here's an implementation of the above. Note how we can use a with statement to do the first and last steps in one (and other benefits).
lines = ['Line one', 'Line two', 'Line three']
with open('your_file.txt', 'w') as f:
for l in lines:
f.write(l + '\n')

Saving a flat-file through Vim add an invisible byte to the file that creates a new line

The title is not really specific, but I have trouble identifying the correct key words as I'm not sure what is going on here. For the same reason, it is possible that my question has a duplicate, as . If that's the case: sorry!
I have a Linux application that receive data via flat files. I don't know exactly how those files are generated, but I can read them without any problem. Those are short files, only a line each.
For test purpose, I tried to modify one of those files and reinjected it again in the application. But when I do that I can see in the log that it added a mysterious page break at the end of the message (resulting in the application not recognising the message)...
For the sake of example, let's say I receive a flat file, named original, that contains the following:
ABCDEF
I make a copy of this file and named it copy.
If I compare those two files using the "diff" command, it says they are identical (as I expect them to be)
If I open copy via Vi and then quit without changing nor saving anything and then use the "diff" command, it says they are identical (as I also expect them to be)
If I open copy via Vi and then save it without changing anything and then use the "diff" command, I have the following (I added the dot for layout purpose):
diff original copy
1c1
< ABCDEF
\ No newline at end of file
---
.> ABCDEF
And if I compare the size of my two files, I can see that original is 71 bytes when copy is 72.
It seems that the format of the file change when I save the file. I first thought of an encoding problem, so I used the ":set list" command on Vim to see the invisible characters. But for both files, I can see the following:
ABCDEF$
I have found other ways to do my test, But this problem still bugged me and I would really like to understand it. So, my two questions are:
What is happening here?
How can I modify a file like that without creating this mysterious page break?
Thank you for your help!
What happens is that Vim is set by default to assume that the files you edit end with a "newline" character. That's normal behavior in UNIX-land. But the "files" your program is reading look more like "streams" to me because they don't end with a newline character.
To ensure that those "files" are written without a newline character, set the following options before writing:
:set binary noeol
See :help 'eol'.

In Vim, what is the "alternate file"?

I just ran :help registers in Vim and noticed that # 'contains the name of the alternate file'.
I have seen an example for renaming files that goes like this:
" Save the current file, foo.txt, as bar.txt
:w bar.txt
" Start editing bar.txt
:e#
So apparently in that case, the file you just saved out is the "alternate file."
Can someone give me a more general definition for the "alternate file" and what else you might use it for?
The alternate file is the file that was last edited in the current window. Actually when you use some command to open a new buffer, if the buffer that was displayed had a filename associated with it, that filename is recorded as alternate file name.
See :help alternate-file.
Very useful for...
Pasting in the name of a file I've just been looking at into the current file.
You can use <C-R># for this in insert mode or "#p in normal mode.
Not that useful for...
Jumping back and forth between two files. It does the job very well, but this is just something I don't generally need to do.
Even in the example given, I'd probably use:saveas bar.txt instead.
An Example:
Say if you're doing a bit of C programming and want to call some function. You can't remember the name of the function, so you place a mark on your current location mA and jump into several different files using tags or grep to find out where the function is declared and what it's actually called.
Ah - found it. You can copy the name and return to the mark yiw'A
Uh-oh - we also need to #include the file! Easy - just use the alternate file name register to paste the file name in... Gi#include"<C-R>#"
Be pleased that you've avoided the distraction of having to go back to the function's declaration and copy out the file name via :let #"=#% or something similar.
What I'd rather do when jumping between files:
When editing two files, it's probably easier to split them, so you can keep both on screen at the same time. If I'm editing 2 files I'll usually be comparing them in some way.
Usually I'm interested in 1-3 files (any more and I get confused). I'll often jump into or directly open many other files. Marking the interesting files, or traversing the jump list is usually the way to get around in this case.
If you're editing C/C++ where you're switching between a file and it's header, use a plugin! It will be much more convenient.
I use it in the buffer context to return to the last buffer that I was editing
vim foo bar
:n
:e#
will take you back to foo in that case
I 've always interpreted the "alternate file" as being the "previous file", so it is an handy way to jump back to the buffer you were editing.

Resources