Iterating through python string array gives unexpected output - python

I was debugging some python code and as any begginer, I'm using print statements. I narrowed down the problem to:
paths = ("../somepath") #is this not how you declare an array/list?
for path in paths:
print path
I was expecting the whole string to be printed out, but only . is. Since I planned on expanding it anyway to cover more paths, it appears that
paths = ("../somepath", "../someotherpath")
fixes the problem and correctly prints out both strings.
I'm assuming the initial version treats the string as an array of characters (or maybe that's just the C++ in me talking) and just prints out characters.?...??
I'd still like to know why this happens.

("../somepath")
is nothing but a string covered in parenthesis. So, it is the same as "../somepath". Since Python's for loop can iterate through any iterable and a string happens to be an iterable, it prints one character at a time.
To create a tuple with one element, use comma at the end
("../somepath",)
If you want to create a list, you need to use square brackets, like this
["../somepath"]

paths = ["../somepath","abc"]
This way you can create list.Now your code will work .
paths = ("../somepath", "../someotherpath") this worked as it formed a tuple.Which again is a type of non mutable list.

Tested it and the output is one character per line
So all is printed one character per character
To get what you want you need
# your code goes here
paths = ['../somepath'] #is this not how you declare an array/list?
for path in paths:
print path

Related

glob syntax working not as expected( [ ] *)

I have a folder containing 4 files.
Keras_entity_20210223-2138.h5
intent_tokens.pickle
word_entity_set_20210223-2138.pickle
LSTM_history.h5
I used code:
NER_MODEL_FILEPATH = glob.glob("model/[Keras_entity]*.h5")[0]
It's working correctly since NER_MODEL_FILEPATH is a list only containing the path of that Keras_entity file. Not picking that other .h5 file.
But when I use this code:
WORD_ENTITY_SET_FILEPATH = glob.glob("model/[word_entity_set]*.pickle")[0]
It's not working as expected, rather than picking up only that word_entity_set file,
this list contains both of those two pickle files.
Why would this happen?
Simply remove the square brackets: word_entity_set*.pickle
Per the docs:
[seq] matches any character in seq
So word_entity_set_20210223-2138.pickle is matched because it starts with a w, and intent_tokens.pickle is matched because it starts with an i.
To be clear, it is working as expected. Your expectations were incorrect.
Your code selects intent_tokens.pickle and word_entity_set_20210223-2138.pickle because your glob is incorrect. Change the glob to "word_entity_set*.pickle"
When you use [<phrase>]*.pickle, you're telling the globber to match one of any of the characters in <phrase> plus any characters, plus ".pickle". So "wordwordword.pickle" will match, so will:
wwww.pickle
.pickle
w.pickle
But
xw.pickle
foobar.pickle
will not.
There are truly infinite permutations.

Python function accepting a string, but not when its inside a variable

I have the following code (it changes the string/filepath, replacing the numbers at the end of the filename + the file extension, and replaces that with "#.exr"). I hope I made the problem replicatable below.
I was doing it this way because the filename can be typed in all kinds of ways, for example:
r_frame.003.exr (but also)
r_12_frame.03.exr
etc.
import pyseq
import re
#create render sequence list
selected_file = 'H:/test/r_frame1.exr'
without_extention = selected_file.replace(".exr", "")
my_regex_pattern = r"\d+\b"
sequence_name_with_replaced_number = re.sub(my_regex_pattern, "#.exr" ,without_extention)
mijn_sequences = fileseq.findSequencesOnDisk(sequence_name_with_replaced_number)
If I print the "sequence_name_with_replaced_number" value, this results in the console in:
'H:/test/r_frame#.exr'
When I use that variable inside that function like this:
mijn_sequences = fileseq.findSequencesOnDisk(sequence_name_with_replaced_number)
Then it does not work.
But when I manually replace that last line into:
mijn_sequences = fileseq.findSequencesOnDisk('H:/test/r_frame#.exr')
Then it works fine. (it's the seems like same value/string)
But this is not an viable option, the whole point of the code if to have the computer do this for thousands of frames.
Anybody any idea what might be the cause of this?
I already tried re-converting the variable into a string with str()
I tried other ways like using an f-string, I wasn't sure how to convert it into a raw string since the variable already exists.
After this I will do simple for loop going trough al the files in that sequence. The reason I'm doing this workflow is to delete the numbers before the .exr file extensions and replace them with # signs. (but ognoring all the bumbers that are not at the end of the filename, hence that regex above. Again, the "sequence_name_with_replaced_number" variable seems ok in the console. It spits out: 'H:/test/r_frame#.exr' (that's what I need it to be)
It's fixed!
the problem was correct, every time I did a cut and past from the variable value in the console and treated it as manual input it worked.
Then I did a len() of both values, and there was a difference by 2!
What happend?
The console added the ''
But in the generated variable it had those baked in as extra letters.
i fixed it by adding
cleaned_sequence = sequence_name_with_replaced_number[1:-1]
so 'H:/test/r_frame1.exr' (as the console showed me)
was not the same as 'H:/test/r_frame1.exr' (what I inserted manually, because I added these marks, in the console there are showed automatically)

Remove duplicates from a list in Python

I have a python script which parses an xml file and then gives me the required information. My output looks like this, and is 100% correct:
output = ['77:275,77:424,77:425,77:426,77:427,77:412,77:413,77:414,77:412,77:413,77:414,77:412,77:413,77:414,77:412,77:413,77:414,77:431,77:432,77:433,77:435,77:467,77:470,77:471,77:484,77:485,77:475,77:476,77:437,77:438,77:439,77:440,77:442,77:443,77:444,77:445,77:446,77:447,77:449,77:450,77:451,77:454,77:455,77:456,77:305,77:309,77:496,77:497,77:500,77:504,77:506,77:507,77:508,77:513,77:515,77:514,77:517,77:518,77:519,77:521,77:522,77:523,77:403,77:406,77:404,77:405,77:403,77:406,77:404,77:405,77:526,77:496,77:497,77:500,77:504,77:506,77:507,77:508,77:513,77:515,77:514,77:517,77:518,77:519,77:521,77:522,77:523,77:403,77:406,77:404,77:405,77:403,77:406,77:404,77:405,77:526,77:317,77:321,77:346,77:349,77:350,77:351,77:496,77:497,77:500,77:504,77:506,77:507,77:508,77:513,77:515,77:514,77:517,77:518,77:519,77:521,77:522,77:523,77:403,77:406,77:404,77:405,77:403,77:406,77:404,77:405,77:526,77:496,77:497,77:500,77:504,77:506,77:507,77:508,77:513,77:515,77:514,77:517,77:518,77:519,77:521,77:522,77:523,77:403,77:406,77:404,77:405,77:403,77:406,77:404,77:405,77:526,77:362,77:367,77:369,77:374,77:370,77:372,77:373,77:387,77:388,77:389,77:392,77:393,77:394,77:328,77:283,77:284,77:285,77:288,77:289,77:290,77:292,']
It is all fine, but I want to remove the duplicate elements in an element, like in the case above. I tried using the OrderedDict package or just simple list(set(output)), but obvoiusly they both didn't work. Does anyone have a tip for me on how to solve this problem.
You have one element in a list. If you expected it to be treated as separate elements, you need to explicitly split it.
You could split the string on the ',' comma character into a list with str.split():
separate_elements = output[0].split(',')
after which you can use set() (unordered) or OrderedDict (maintaining order) and re-join the string if you still need just the one string object:
','.join(set(separate_elements))
You can put that back into a list with just one element, but there is little point if all you ever handle is that one string.

striplines() not working when using finditer python

I am trying to convert a multiline string to a single list which should be possible using splitlines() but for some reason it continues to convert each line into a list instead of processing all the lines at once. I tried to do it out of the for loop but doesnt seem to have any effect. I need the lines as a single list to use it another function. Below is how I get the multiline into a single variable. What am I missing???
multiline_string_final = []
for match_multiline in re.finditer(r'(^(\w+):\sThis particular string\s*|This particular string\s*)\{\s(\w+)\s\{(.*?)\}', string, re.DOTALL):
multi_line_string = match_multiline.group(4)
print multiline_string
This last print statement prints out the strings like this:
blah=0; blah_blah=1; Foo=3;
blah=4; blah_blah=5; Foo=0;
However I need:
['blah=0; blah_blah=1; Foo=3;''blah=4; blah_blah=5; Foo=0;']
I understand it has to be something with the finditer but cant seem to rectify.
Your new problem also has nothing to do with finditer. (Also, your code is still not an MCVE, you still haven't shown us the sample input data, etc., making it harder to help you.)
From this desired output:
['blah=0; blah_blah=1; Foo=3;''blah=4; blah_blah=5; Foo=0;']
I'm pretty sure what you're looking for is to get a list of the matches, instead of printing out each match on its own. That isn't a valid list, because it's missing the comma between the elements,* but I'll assume that's a typo from you making up data instead of building an MCVE and copying and pasting the real output.
Anyway, to get a list, you have to build a list. Printing things to the screen doesn't build anything. So, try this:
multiline_string_final.append(multiline_string)
Then, at the end—not inside the loop, only after the loop has finished—you can print that out:
print multiline_string_final
And it'll look like this:
['blah=0; blah_blah=1; Foo=3;',
'blah=4; blah_blah=5; Foo=0;']
* Actually, it is a valid list, because adjacent strings get concatenated… but it's not the string you wanted, and not a format Python would ever print out for you.
The problem has nothing to do with the finditer, it's that you're doing the wrong thing:
for line in multiline_string:
print multiline_string.splitlines()
If multiline_string really is a multiline string, then for line in multiline_string will iterate over the characters of that string.
Then, within the loop, you completely ignore line anyway, and instead print multiline_string.splitlines()).
So, if multiline_string is this:
abc
def
Then you'll print ['abc\n', 'def\n'] 8 times in a row. That's not what you want (or what you described).
What you want to do is:
split the string into lines
loop over those lines, not over the original un-split string
print each line, not the whole thing
So:
for line in multiline_string.splitlines():
print line

Compare & manipulate strings with python

I've written an XML parser in Python and have just added functionality to read a further script from a different directory.
I've got two args, first is the path where I'm parsing XML. Second is a string in another XML file which I want to match with the first path;
arg1 = \work\parser\main\tools\app\shared\xml\calculators\2012\example\calculator
path = calculators/2012/example/calculator
How can I compare the two strings to match identify that they're both referencing the same thing and also, how can I strip calculator from either string so I can store that & use it?
edit
Just had a thought. I have used a Regex to get the year out of the path already with year = re.findall(r"\.(\d{4})\.", path) following a problem Python has with numbers when converting the path to an import statement.
I could obviously split the strings and use a regex to match the path as a pattern in arg1 but this seems a long way round. Surely there's a better method?
Here I am assuming you are actually talking about strings, and not file paths - for which #mgilson's suggestion is better
How can I compare the two strings to match identify that they're both
referencing the same thing
Well first you need to identify what you mean by "the same thing"
At first glance it seems that if the the second string ends with the first string with the reversed slash, you have a match.
arg1 = r'\work\parser\main\tools\app\shared\xml\calculators\2012\example\calculator'
arg2 = r'calculators/2012/example/calculator'
>>> arg1.endswith(arg2.replace('/','\\'))
True
and also, how can I strip calculator from
either string so I can store that & use it?
You also need to decide if you want to strip the first calculator, the last calculator or any occurance of calculator in the string.
If you just want to remove the last string after the separator, then its simply:
>>> arg2.split('/')[-1]
'calculator'
Now to get the orignal string back, without the last bit:
>>> '/'.join(arg2.split('/')[:-1])
'calculators/2012/example'
check out os.path.samefile:
http://docs.python.org/library/os.path.html#os.path.samefile
and os.path.dirname:
http://docs.python.org/library/os.path.html#os.path.dirname
or maybe os.path.basename (I'm not sure what part of the string you want to keep).
Here, try this:
arg1 = "\work\parser\main\tools\app\shared\xml\calculators\2012\example\calculator"
path = "calculators/2012/example/calculator"
arg1=arg1.replace("/","\\")
path=path.replace("/","\\")
if str(arg1).endswith(str(path)) or str(path).endswith(str(arg1)):
print "Match"
That should work for your needs. Cheers :)

Categories