retrieving name from number ID - python

I have a code that takes data from online where items are referred to by a number ID, compared data about those items, and builds a list of item ID numbers based on some criteria. What I'm struggling with is taking this list of numbers and turning it into a list of names. I have a text file with the numbers and corresponding names but am having trouble using it because it contains multi-word names and retains the \n at the end of each line when i try to parse the file in any way with python. the text file looks like this:
number name\n
14 apple\n
27 anjou pear\n
36 asian pear\n
7645 langsat\n
I have tried split(), as well as replacing the white space between with several difference things to no avail. I asked a question earlier which yielded a lot of progress but still didn't quite work. The two methods that were suggested were:
d = dict()
f=open('file.txt', 'r')
for line in f:
number, name = line.split(None,1)
d[number] = name
this almost worked but still left me with the \n so if I call d['14'] i get 'apple\n'. The other method was:
import re
f=open('file.txt', 'r')
fr=f.read()
r=re.findall("(\w+)\s+(.+)", fr)
this seemed to have gotten rid of the \n at the end of every name but leaves me with the problem of having a tuple with each number-name combo being a single entry so if i were to say r[1] i would get ('14', 'apple'). I really don't want to delete each new line command by hand on all ~8400 entries...
Any recommendations on how to get the corresponding name given a number from a file like this?

In your first method change the line ttn[number] = name to ttn[number] = name[:-1]. This simply strips off the last character, and should remove your \n.

names = {}
with open("id_file.txt") as inf:
header = next(inf, '') # skip header row
for line in inf:
id, name = line.split(None, 1)
names[int(id)] = name.strip()
names[27] # => 'anjou pear'

Use this to modify your first approach:
raw_dict = dict()
cleaned_dict = dict()
Assuming you've imported file to dictionary:
raw_dict = {14:"apple\n",27:"anjou pear\n",36 :"asian pear\n" ,7645:"langsat\n"}
for keys in raw_dict:
cleaned_dict[keys] = raw_dict[keys][:len(raw_dict[keys])-1]
So now, cleaned_dict is equal to:
{27: 'anjou pear', 36: 'asian pear', 7645: 'langsat', 14: 'apple'}
*Edited to add first sentence.

Related

Python - Intersection of sets returns only the first value

If I input three names (Rolf, Charlie, Mike) the friends_nearby_set intersection returns only the first input (Rolf).
If I input (Charlie, Rolf, Mike) the friends_nearby_set intersection returns only (Charlie).
Expected output from friends_nearby_set intersection should be (Rolf, Charlie).
The author's code returns correct value in video tutorial I'm watching. But for some reason for me it isn't return a proper intersection. Any explanation?
friends = input('Enter three friends name, separated by commas (no spaces, please): ').split(',')
people = open('people.txt', 'r')
people_nearby = [line.strip() for line in people.readlines()]
people.close()
friends_set = set(friends)
people_nearby_set = set(people_nearby)
friends_nearby_set = friends_set.intersection(people_nearby_set)
nearby_friends_file = open('nearby_friends.txt', 'w')
for friend in friends_nearby_set:
print(f'{friend} is nearby! Meet up with them.')
nearby_friends_file.write(f'{friend}\n')
nearby_friends_file.close()
Here is a screenshot during debugging.
The following is the output before you input the names Enter three friends name, separated by commas (no spaces, please)
python sets might be case sensitive try to remove space between comma and the next name
here is example
set_1 = {'Rolf', ' Charlie'}
set_2 = {'Rolf', 'Charlie'}
print(set_1.intersection(set_2))
output
{'Rolf'}
not {'Rolf', 'Charlie'} because the first got space before. so make attention when you input names input them like Rolf,Charlie,Mike
and also try to remove extra spaces before and after the input like the following
friends = input('Enter three friends name, separated by commas (no spaces, please): ').strip().split(',')
And I saw here how you're writing might be the source of the error to
just open file in the append mode instead of writing mode
nearby_friends_file = open('nearby_friends.txt', 'w')
to
nearby_friends_file = open('nearby_friends.txt', 'a')
because w will overwrite the file while a will append on the file

Rewriting Single Words in a .txt with Python

I need to create a Database, using Python and a .txt file.
Creating new items is no Problem,the inside of the Databse.txt looks like this:
Index Objektname Objektplace Username
i.e:
1 Pen Office Daniel
2 Saw Shed Nic
6 Shovel Shed Evelyn
4 Knife Room6 Evelyn
I get the index from a QR-Scanner (OpenCV) and the other informations are gained via Tkinter Entrys and if an objekt is already saved in the Database, you should be able to rewrite Objektplace and Username.
My Problems now are the following:
If I scan the Code with the index 6, how do i navigate to that entry, even if it's not in line 6, without causing a Problem with the Room6?
How do I, for example, only replace the "Shed" from Index 4 when that Objekt is moved to f.e. Room6?
Same goes for the Usernames.
Up until now i've tried different methods, but nothing worked so far.
The last try looked something like this
def DBChange():
#Removes unwanted bits from the scanned code
data2 = data.replace("'", "")
Index = data2.replace("b","")
#Gets the Data from the Entry-Widgets
User = Nutzer.get()
Einlagerungsort = Ort.get()
#Adds a whitespace at the end of the Entrys to seperate them
Userlen = len(User)
User2 = User.ljust(Userlen)
Einlagerungsortlen = len(Einlagerungsort)+1
Einlagerungsort2 = Einlagerungsort.ljust(Einlagerungsortlen)
#Navigate to the exact line of the scanned Index and replace the words
#for the place and the user ONLY in this line
file = open("Datenbank.txt","r+")
lines=file.readlines()
for word in lines[Index].split():
List.append(word)
checkWords = (List[2],List[3])
repWords = (Einlagerungsort2, User2)
for line in file:
for check, rep in zip(checkWords, repWords):
line = line.replace(check, rep)
file.write(line)
file.close()
Return()
Thanks in advance
I'd suggest using Pandas to read and write your textfile. That way you can just use the index to select the approriate line. And if there is no specific reason to use your text format, I would switch to csv for ease of use.
import pandas as pd
def DBChange():
#Removes unwanted bits from the scanned code
# I haven't changed this part, since I guess you need this for some input data
data2 = data.replace("'", "")
Indexnr = data2.replace("b","")
#Gets the Data from the Entry-Widgets
User = Nutzer.get()
Einlagerungsort = Ort.get()
# I removed the lines here. This isn't necessary when using csv and Pandas
# read in the csv file
df = pd.read_csv("Datenbank.csv")
# Select line with index and replace value
df.loc[Indexnr, 'Username'] = User
df.loc[Indexnr, 'Objektplace'] = Einlagerungsort
# Write back to csv
df.to_csv("Datenbank.csv")
Return()
Since I can't reproduce your specific problem, I haven't tested it. But something like this should work.
Edit
To read and write text-file, use ' ' as the seperator. (I assume all values do not contain spaces, and your text file now uses 1 space between values).
reading:
df = pd.read_csv('Datenbank.txt', sep=' ')
Writing:
df.to_csv('Datenbank.txt', sep=' ')
First of all, this is a terrible way to store data. My suggestion is not particularily well code, don't do this in production! (edit
newlines = []
for line in lines:
entry = line.split()
if entry[0] == Index:
#line now is the correct line
#Index 2 is the place, index 0 the ID, etc
entry[2] = Einlagerungsort2
newlines.append(" ".join(entry))
# Now write newlines back to the file

String Cutting with multiple lines

so i'm new to python besides some experience with tKintner (some GUI experiments).
I read an .mbox file and copy the plain/text in a string. This text contains a registering form. So a Stefan, living in Maple Street, London working for the Company "MultiVendor XXVideos" has registered with an email for a subscription.
Name_OF_Person: Stefan
Adress_HOME: London, Maple
Street
45
Company_NAME: MultiVendor
XXVideos
I would like to take this data and put in a .csv row with column
"Name", "Adress", "Company",...
Now i tried to cut and slice everything. For debugging i use "print"(IDE = KATE/KDE + terminal... :-D ).
Problem is, that the data contains multiple lines after keywords but i only get the first line.
How would you improve my code?
import mailbox
import csv
import email
from time import sleep
import string
fieldnames = ["ID","Subject","Name", "Adress", "Company"]
searchKeys = [ 'Name_OF_Person','Adress_HOME','Company_NAME']
mbox_file = "REG.mbox"
export_file_name = "test.csv"
if __name__ == "__main__":
with open(export_file_name,"w") as csvfile:
writer = csv.DictWriter(csvfile, dialect='excel',fieldnames=fieldnames)
writer.writeheader()
for message in mailbox.mbox(mbox_file):
if message.is_multipart():
content = '\n'.join(part.get_payload() for part in message.get_payload())
content = content.split('<')[0] # only want text/plain.. Ill split #right before HTML starts
#print content
else:
content = message.get_payload()
idea = message['message-id']
sub = message['subject']
fr = message['from']
date = message['date']
writer.writerow ('ID':idea,......) # CSV writing will work fine
for line in content.splitlines():
line = line.strip()
for pose in searchKeys:
if pose in line:
tmp = line.split(pose)
pmt = tmp[1].split(":")[1]
if next in line !=:
print pose +"\t"+pmt
sleep(1)
csvfile.closed
OUTPUT:
OFFICIAL_POSTAL_ADDRESS =20
Here, the lines are missing..
from file:
OFFICIAL_POSTAL_ADDRESS: =20
London, testarossa street 41
EDIT2:
#Yaniv
Thank you, iam still trying to understand every step, but just wanted to give a comment. I like the idea to work with the list/matrix/vector "key_value_pairs"
The amount of keywords in the emails is ~20 words. Additionally, my values are sometimes line broken by "=".
I was thinking something like:
Search text for Keyword A,
if true:
search text from Keyword A until keyword B
if true:
copy text after A until B
Name_OF_=
Person: Stefan
Adress_
=HOME: London, Maple
Street
45
Company_NAME: MultiVendor
XXVideos
Maybe the HTML from EMAIL.mbox is easier to process?
<tr><td bgcolor=3D"#eeeeee"><font face=3D"Verdana" size=3D"1">
<strong>NAM=
E_REGISTERING_PERSON</strong></font></td><td bgcolor=3D"#eeeeee"><font
fac=e=3D"Verdana" size=3D"1">Stefan </font></td></tr>
But the "=" are still there
should i replace ["="," = "] with "" ?
I would go for a "routine" parsing loop over the input lines, and maintain a current_key and current_value variables, as a value for a certain key in your data might be "annoying", and spread across multiple lines.
I've demonstrated such parsing approach in the code below, with some assumptions regarding your problem. For example, if an input line starts with a whitespace, I assumed it must be the case of such "annoying" value (spread across multiple lines). Such lines would be concatenated into a single value, using some configurable string (the parameter join_lines_using_this). Another assumption is that you might want to strip whitespaces from both keys and values.
Feel free to adapt the code to fit your assumptions on the input, and raise Exceptions whenever they don't hold!
# Note the usage of .strip() in some places, to strip away whitespaces. I assumed you might want that.
def parse_funky_text(text, join_lines_using_this=" "):
key_value_pairs = []
current_key, current_value = None, ""
for line in text.splitlines():
line_split = line.split(':')
if line.startswith(" ") or len(line_split) == 1:
if current_key is None:
raise ValueError("Failed to parse this line, not sure which key it belongs to: %s" % line)
current_value += join_lines_using_this + line.strip()
else:
if current_key is not None:
key_value_pairs.append((current_key, current_value))
current_key, current_value = None, ""
current_key = line_split[0].strip()
# We've just found a new key, so here you might want to perform additional checks,
# e.g. if current_key not in sharedKeys: raise ValueError("Encountered a weird key?! %s in line: %s" % (current_key, line))
current_value = ':'.join(line_split[1:]).strip()
# Don't forget the last parsed key, value
if current_key is not None:
key_value_pairs.append((current_key, current_value))
return key_value_pairs
Example usage:
text = """Name_OF_Person: Stefan
Adress_HOME: London, Maple
Street
45
Company_NAME: MultiVendor
XXVideos"""
parse_funky_text(text)
Will output:
[('Name_OF_Person', 'Stefan'), ('Adress_HOME', 'London, Maple Street 45'), ('Company_NAME', 'MultiVendor XXVideos')]
You indicate in the comments that your input strings from the content should be relatively consistent. If that is the case, and you want to be able to split that string across multiple lines, the easiest thing to do would be to replace \n with spaces and then just parse the single string.
I've intentionally constrained my answer to using just string methods rather than inventing a huge function to do this. Reason: 1) Your process is already complex enough, and 2) your question really boils down to how to process the string data across multiple lines. If that is the case, and the pattern is consistent, this will get this one off job done
content = content.replace('\n', ' ')
Then you can split on each of the boundries in your consistently structured headers.
content = content.split("Name_OF_Person:")[1] #take second element of the list
person = content.split("Adress_HOME:")[0] # take content before "Adress Home"
content = content.split("Adress_HOME:")[1] #take second element of the list
address = content.split("Company_NAME:")[0] # take content before
company = content.split("Adress_HOME:")[1] #take second element of the list (the remainder) which is company
Normally, I would suggest regex. (https://docs.python.org/3.4/library/re.html). Long term, if you need to do this sort of thing again, regex is going to pay dividends on time spend munging data. To make a regex function "cut" across multiple lines, you would use the re.MULTILINE option. So it might endup looking something like re.search('Name_OF_Person:(.*)Adress_HOME:', html_reg_form, re.MULTILINE)

Removing white space and colon

I have a file with a bunch of numbers that have white spaces and colons and I am trying to remove them. As I have seen on this forum the function line.strip.split() works well to achieve this. Is there a way of removing the white space and colon all in one go? Using the method posted by Lorenzo I have this:
train = []
with open('C:/Users/Morgan Weiss/Desktop/STA5635/DataSets/dexter/dexter_train.data') as train_data:
train.append(train_data.read().replace(' ','').replace(':',''))
size_of_train = np.shape(train)
for i in range(size_of_train[0]):
for j in range(size_of_train[1]):
train[i][j] = int(train[i][j])
print(train)
Although I get this error:
File "C:/Users/Morgan Weiss/Desktop/STA5635/Homework/Homework_1/HW1_Dexter.py", line 11, in <module>
for j in range(size_of_train[1]):
IndexError: tuple index out of range
I think the above syntax is not correct, but anyways as per your question, you can use replace function present in python.
When reading each line as a string from that file you can do something like,
train = []
with open('/Users/sushant.moon/Downloads/dexter_train.data') as f:
list = f.read().split()
for x in list:
data = x.split(':')
train.append([int(data[0]),int(data[1])])
# this part becomes redundant as i have already converted str to int before i append data to train
size_of_train = np.shape(train)
for i in range(size_of_train[0]):
for j in range(size_of_train[1]):
train[i][j] = int(train[i][j])
Here I am using replace function to replace space with blank string, and similar with colon.
You did not provide an example of what your input file looks like so we can only speculate what solution you need. I'm going to suppose that you need to extract integers from your input text file and print their values.
Here's how I would do it:
Instead of trying to eliminate whitespace characters and colons, I will be searching for digits using a regular expression
Consecutive digits would constitute a number
I would convert this number to an integer form.
And here's how it would look like:
import re
input_filename = "/home/evens/Temporaire/Stack Exchange/StackOverflow/Input_file-39359816.txt"
matcher = re.compile(r"\d+")
with open(input_filename) as input_file:
for line in input_file:
for digits_found in matcher.finditer(line):
number_in_string_form = digits_found.group()
number = int(number_in_string_form)
print(number)
But before you run away with this code, you should continue to learn Python because you don't seem to grasp its basic elements yet.

Python read text file into dictionary, list of strings

I am trying to read a text file into a dictionary.
The text file contains a person's name, networks, and friends' names.
The key for dictionary is person's name, and value is that person's networks
Here is the text file:
Pritchett, Mitchell\n
Law Association\n
Dunphy, Claire\n
Tucker, Cameron\n
Dunphy, Luke\n
\n\n
Tucker, Cameron\n
Clown School\n
Wizard of Oz Fan Club\n
Pritchett, Mitchell\n
Pritchett, Gloria\n
\n\n
Dunphy, Alex\n
Orchestra\n
Chess Club\n
Dunphy, Luke\n
Here is what I did
def person_to_networks(file):
I get an error for the line 'if "\n" and "," in lst[0]'. It says list index out of range.
Please help me. I can't figure out what is wrong with this code.
you get that error because you are initializing your lst to be empty [ ], and then you check the first element which does not exist.
you say that you want to turn your file into a dictionary, I suggest this simpler code for that:
import re # import regex library
# open the file and import your data
f = open('data', 'r')
data = f.read()
f.close()
# initialize your data to be processed
dict = {}
data = data.replace('\\n', '') # remove \n characters
data = data.split('\n\n') # split it into blocks
for block in data:
block = block.split('\n') # split each bock into lines
nets = []
for line in block:
if ',' not in line and line != '': # find networks
nets.append(line)
block[0] = re.sub(r'(\w+),\s(\w+)', r'\2, \1', block[0]) # ADDED to switch first name and last name
dict.update({block[0]: nets}) # update the result dictionary
print dict
and this will give you this result for your suggested file example:
{'Pritchett, Mitchell': ['Law Association'], 'Tucker, Cameron': ['Clown School', 'Wizard of Oz Fan Club'], 'Dunphy, Alex': ['Orchestra', 'Chess Club']}
if this is not what you want, please describe in more details what it is.
Edit: in order to switch the first name and last name you can add just that single line to make that switch before you update the dictionary. I added that line in the code above, it uses a regex (don't forget to add "import re" like in the beginning of my code) :
'(\w+),\s(\w+)' # used to find the first name and last name and store them in \1 and \2 match groups.
'\2, \1' # to replace the place of the match groups as required.
OR '\2 \1' # if you don't want the comma
and you can manipulate it however you like, e.g: you can remove the , or something like that.
and after the switching the output will become like:
{'Alex, Dunphy': ['Orchestra', 'Chess Club'], 'Cameron, Tucker': ['Clown School', 'Wizard of Oz Fan Club'], 'Mitchell, Pritchett': ['Law Association']}
Edit: another way to switch between the first and last names (remove the "import re" and the previously added line and replace it with these three lines with the same indent):
s = block[0].split(', ')
s.reverse()
block[0] = ', '.join(s) # or use ' '.join(s) if you don't want the comma
hope this helps.
Because the first time through the loop, you're trying to access lst[0], when lst is still [].
First line at least, lst is empty list ([]).
You should append some values to lst first.
Probably, you want to did following:
if "\n" and "," in lst[0]:
to
if "\n" and "," in line[0]:
,
elif "," not in lst[1:]:
to
elif "," not in line[1:]:
new_person_friends in the last line is not defined. You need fix that to right one.
When line is "\n", lst will clear after networks's update.
And your data have "\n\n". That means 2 consecutive empty lines.
In the second "\n", lst is empty list because the first "\n" was processed.
You need fix your code to avoid that problem like this: if line == '\n' and lst != []:

Categories

Resources