Хорошая работа, приложив усилия, прежде чем просить о помощи.Вот мои изменения в вашем коде.Я сохранил ваш код и прокомментировал его, чтобы вы знали, что я делал.Использование регулярных выражений - лучший выбор для вас в этой ситуации.Я использую те же петли, что и вы.Я не разделил описание.Вместо этого я просмотрел полное описание в поисках названий городов с помощью модуля регулярных выражений.Я также не использовал список для сохраненных соответствий.Использование набора гарантирует, что вы не добавляете дубликаты.Проверка, был ли город уже добавлен - еще одна проверка, которая вам не нужна.Я использовал Python 3.7.
Я использовал import re
для импорта модуля регулярных выражений.
import csv
import time
#Raj006 import regular expression module
import re
#import tab-delimited keywords file
f = open('cities_key.txt','r')
#Raj006 Not making the keywords lower. Will match with lower using regex
#allKeywords = f.read().lower().split('\n')
allKeywords = f.read().split('\n')
f.close()
#print(len(allKeywords))
allTexts = []
fullRow = []
with open('adrl_title_desc.csv') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
#the full row for each entry, which will be used to recreate the improved CSV file in a moment
fullRow.append((row['title'], row['description']))
#the column we want to parse for our keywords
#row = row['description'].lower()
#Raj006 not making description lower as regular expression takes care of case-insensitive search.
row = row['description']
allTexts.append(row)
#print(len(row))
#a flag used to keep track of which row is being printed to the CSV file
counter = 0
#use the current date and time to create a unique output filename
timestr = time.strftime("%Y-%m-%d-(%H-%M-%S)")
filename = 'output-' + str(timestr) + '.csv'
#Open the new output CSV file to append ('a') rows one at a time.
with open(filename, 'a') as csvfile:
#define the column headers and write them to the new file
fieldnames = ['title', 'description', 'place']
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
#define the output for each row and then print to the output csv file
writer = csv.writer(csvfile)
#this is the same as before, for currentRow in fullRow:
for entry in allTexts:
#matches = 0
#Raj006 Changed this to set to make sure the list is unique (which is basically the definiton of the set)
storedMatches = set()
#Raj006 looping through all cities and checking if the city name exists in the description.
#Raj006 re.search looks for the lookup word in the entire string (re.search(lookupword,string)).
for eachcity in allKewords:
if re.search('\\b'+eachcity+'\\b',entry,re.IGNORECASE):
#Adding the matched city to the set
storedMatches.add(eachcity)
#for each entry:
#HOW TO RESOLVE MULTI-PART NAMES? e.g. Santa Barbara
#allWords = entry.split(' ')
#for words in allWords:
#remove punctuation that will interfere with matching
#words = words.replace(',', '')
#words = words.replace('.', '')
#words = words.replace(';', '')
#if a keyword match is found, store the result.
#if words in allKeywords:
#if words in storedMatches:
#continue
#else:
#storedMatches.append(words)
#matches += 1
#send any matches to a new row of the csv file.
#if matches == 0:
#Raj006 Just using the length of the set to determine if any matches found. Reducing one more unnecessary check.
if len(storedMatches)==0:
newRow = fullRow[counter]
else:
matchTuple = tuple(storedMatches)
newRow = fullRow[counter] + matchTuple
#write the result of each row to the csv file
writer.writerows([newRow])
counter += 1
Обновление: в re.search добавлен регистр игнорирования.
Я улучшилприведенный выше код для удаления ненужных циклов и путаницы в именах переменных.У меня нет исходного файла, поэтому я не смог его проверить.Если я обнаружу какие-либо проблемы, я обновлю их позже.
import csv
import time
import re
allCities = open('cities_key.txt','r').readlines()
timestr = time.strftime("%Y-%m-%d-(%H-%M-%S)")
with open('adrl_title_desc.csv') as descriptions,open('output-' + str(timestr) + '.csv', 'w', newline='') as output:
descriptions_reader = csv.DictReader(descriptions)
fieldnames = ['title', 'description', 'cities']
output_writer = csv.DictWriter(output, delimiter='|', fieldnames=fieldnames)
output_writer.writeheader()
for eachRow in descriptions_reader:
title = eachRow['title']
description = eachRow['description']
citiesFound = set()
for eachcity in allCities:
eachcity=eachcity.strip()
if re.search('\\b'+eachcity+'\\b',description,re.IGNORECASE):
citiesFound.add(eachcity)
if len(citiesFound)>0:
output_writer.writerow({'title': title, 'description': description, 'cities': ", ".join(citiesFound)})
Этот код имеет разделитель csv, установленный на |
вместо ,
, как я использовал его для городов.
Тестовые файлы.towns_key.txt
San Francisco
San Gabriel
San Jacinto
San Jose
San Juan Capistrano
Haiti
San Mateo
adrl_title_desc.csv
key,title,description
1,title1,"some description here with San Francisco"
2,title2,"some, more description here with Haitian info"
3,title3,"some city not a wordSan Mateo"
4,title4,"some city San Juan Capistrano just normal"
5,title5,"multiple cities in one San Jacinto,San Jose and San Gabriel end"
Вывод кода
title|description|cities
title1|some description here with San Francisco|San Francisco
title4|some city San Juan Capistrano just normal|San Juan Capistrano
title5|multiple cities in one San Jacinto,San Jose and San Gabriel end|San Jacinto, San Jose, San Gabriel
@ itsme, теперь это не должно идти не так с Python 3.x,Я исправил ошибку с '\\b'+eachcity+'\\b'
(пропущенный + знак).Вы не смогли найти совпадений, потому что когда вы по какой-то причине используете readlines()
, он сохраняет окончания строк.Я использовал strip()
, чтобы удалить их.Мне пришлось использовать newline=''
в диалоге открытия файла, так как писатель CSV создавал новую строку после каждой строки.Вы можете видеть, что в моем примере вы не можете найти город для ключа 2 и ключа 3, поскольку города не были отделены в виде слов от остальной части текста.