how to fix if-else problem in calling functions in python? - python-3.x

if file is not None:
content = file.readlines()
if 'I' and 'J' in content:
display_oval()
else:
display_polygon()
in this case,suppose i opened a file containing I&J . i expect to call display_oval() but it calls display_polygon(). when i opened file not containing I&J,display_polygon() calls as expected.
when i replaced 'I' and 'J'with 'I' or 'J',when i opened a file containing I&J,display_oval() works fine. But when i opened file not containing I&J, nothing works.
I want to call display_oval()if file contains I&J and display_polygon()otherwise. how it can be done?

You have a couple of intersecting issues with your code.
Thie first issue is that 'I' and 'J' in content gets grouped as ('I') and ('J' in content), which is surely not what you intend. A string like 'I' is always truthy, so testing in that way is not useful. You probably mean 'I' in content and 'J' in content`.
But that's not enough to fix your code (it makes fewer inputs match, not more). The condition will still not work right because your content is a list of strings, all but the last of which will be newline terminated. When done on a list, the in operator expects exact matches, not substring matches as in does when both arguments are strings.
I'm not exactly sure what fix would be best for that second issue. It depends on the logic of your program, and the contents of your file. If you want to test if I and J show up as individual lines in the file (each separately, on a line with no other characters), you might want to test for 'I\n' in content and 'J\n' in content using the same content you're using now. On the other hand, if you want to check for a capital I and J characters anywhere in the text of the file, without regard to lines, then you probably need to change content instead of changing the matching logic. Use content = file.read() to read the whole file into a single string, rather than a list of strings. Then 'I' in content will do a substring search.

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

searching elements of list in file

The list name is disk and its below:
disks
['5000cca025884d5\n', '5000cca025a1ee6\n']
The file name is p and its below:
c0t5000CCA025884D5Cd0 solaris
/scsi_vhci/disk#g5000cca025884d5c
c0t5000CCA025A1EE6Cd0
/scsi_vhci/disk#g5000cca025a1ee6c
c3t50060E8007DB981Ad1
/pci#400/pci#1/pci#0/pci#8/SUNW,emlxs#0/fp#0,0/ssd#w50060e8007db981a,1
c3t50060E8007DB981Ad2
/pci#400/pci#1/pci#0/pci#8/SUNW,emlxs#0/fp#0,0/ssd#w50060e8007db981a,2
c3t50060E8007DB981Ad3
/pci#400/pci#1/pci#0/pci#8/SUNW,emlxs#0/fp#0,0/ssd#w50060e8007db981a,3
c3t50060E8007DB981Ad4
i want to search elements of a list in file
There are a couple of things to look at here:
I haven't actually used re.match() before, but I can see the first issue: Your list of disks has a newline character after every entry, so that will mess up matches. Also, re.match() only matches from the start of the line. Your lines start with numbers, so you need to search during the line, using re.search(). Finally, you should make it case insensitive; one option to d this is to make everything lowercase just as your disks list is.
try adapting your loop as so:
#.strip() will get rid of new lines and .lower() will make the string lowercase
for line in q:
if re.search(disks[0].strip(),line.lower()):
print line
If that doesn't fix it, I would try making it print out disks[0].strip() and line for every iteration of the loop (not just when it matches the if clause) to make sure it's reading in what you think it is.

Inject a code into the unique function in multiple files (Sublime editor)

Taking the advice of Xaelias I'll modify this post, because the initial question was quite unclear and overcomplicated.
So basically I have multiple script files that need to be edited (too many of them to afford to edit them manually). What I need to do for each script file is to insert a certain code at a specific location inside each of them.
So if my script file was called foo.script, and if the code inside it was as follows:
cut_bar() {
some code...
}
cut_cabbage() {
some code...
}
...
Then I'd like my final look of the foo.script file to be as follows:
cut_bar() {
some code...
message msg_foo_bar
}
cut_cabbage() {
some code...
message msg_foo_cabbage
...
(cut_ is a universal prefix shared by all those functions inside of which the code needs to be added).
Is there any way I can do this in Sublime Text editor? Or is there no other way but to develop a small program that does all of this (in which case, tips would be appreciated likewise!).
We'll try a first solution, which is far from perfect, but might be enough for what you want to do. If it does not work, we'll try another solution.
You want to do a search and replace (⌥⌘F (on mac) or Find→Replace...).
Make sure that the RegEx modifier is active (.* on the left)
Find What: (?<=^cut_)(.*?)(\(\)\h*\{(?:.|\v)*?)(^\}\h*$) (explanations below)
Replace With: \1\2\tmsg_foo_\1\n\3
If it does not work as intended, maybe we'll just need to tweak a little the RegEx. Or maybe we'll need to resort to python and ST plugins!
RegEx explanation:
(?<=^cut_): we want our match to start at the beginning of a line (^) with cut_ this is not captured because as you said, this is a constant, so we don't really care
(.*?): this matches the rest of the name of the method. This is captured and will be \1
(\(\)\h*\{(?:.|\v)*?): we stop the name capture at (), \h is for any horizontal space (spaces or tabs) that could be between the end of the name, and {, then we match every character and \v (vertical space such as new lines) (this is captured as \2)
(^\}\h*$): ... up until we meet a line that starts with }, and might have any kind of horizontal space before the end of the line ($), this is captured as \3
From there, the replace part is kind of straightforward I guess.
\1\2\ is everything we captured but do not want to modify (the name of the method, and its body, except for the last line })
Then we put what you wanted, msg_foo_\1 which will transform into msg_foo_bar for example, and then put back the ending }

Delete text with GREP in Textwrangler

I have the following source code from the Wikipedia page of a list of Games. I need to grab the name of the game from the source, which is located within the title attribute, as follows:
<td><i>007: Quantum of Solace</i><sup id="cite_ref-4" class="reference"><span>[</span>4<span>]</span></sup></td>
As you can see above, in the title attribute there's a string. I need to use GREP to search through every single line for when that occurs, and remove everything excluding:
title="Game name"
I have the following (in TextWrangler) which returns every single occurrence:
title="(.*)"
How can I now set it to remove everything surrounding that, but to ensure it keeps either the string alone, or title="string".
I use a multi-step method to process these kind of files.
First you want to have only one HTML tag per line, GREP works on each line so you want to minimise the need for complicated patterns. I usually replace all: > with >\n
Then you want to develop a pattern for each occurrence of the item you want. In this case 'title=".?"'. Put that in between parentheses (). Then you want add some filling to that statement to find and replace all occurrences of this pattern: .?(title=".?").
Replace everything that matches .?(title=".?").* with \1
Finally, make smart use of the Textwrangler function process lines containing, to filter any remaining rubbish.
Notes
the \1 refers to the first occurrence of a match between () you can also reorder stuff using multiple parentheses and use something like (.?), (.) with \2, \1 to shuffle columns.
Learn how to do lazy regular expressions. The use of ? in these patterns is very powerfull. Basically ? will have the pattern looking for the next occurrence of the next part of the pattern not the latest part that the next part of your pattern occurs.
I've figured this problem out, it was quite simple. Instead of retrieving the content in the title attribute, I'd retrieve the page name.
To ensure I only struck the correct line where the content was, I'd use the following string for searching the code.
(.)/wiki/(.)"
Returning \2
After that, I simply remove any cases where there is HTML code:
<(.*)
Returning ''
Finally, I'll remove the remaining content after the page name:
"(.*)
Returning ''
A bit of cleaning up the spacing and I have a list for all game names.

global submatch()?

I wanted to find a line, then match several words within that line BUT instead of substituting them I would prefer to simply save them (by appending to a register, or exporting to a file).
Is back-referencing (i.e. submatch(1) or \1) doable in this regards, or is that only through the substitution? I realize I could substitute back to the file I am working on - altering it - but I would prefer to export it.
Is there a way to call a function (to save the submatch) within substitute without damaging the file? Or, preferably, use the global search to capture a portion of the line and then pass that as a parameter onto a function call that would do the saving as desired?
Try
:%s/pattern \(saved portion\)/\=[submatch(0), SaverFunc(submatch(1))][0]/
or
:%s/pattern \(saved portion\)\zs/\=SaverFunc(submatch(1))[-1]
. In last case SaverFunc must return either string or number (without explicit :return statement it will return number 0). It does not matter which string or number will be returned: string_or_number[-1] always expands to an empty string.
You might be looking for :h :global and do something like this:
:g/pattern/call func_to_get_and_save_text()
That would call the function on every line matching the given pattern.

Resources