Привет всем! Интересный вопрос был задан мне в Telegram несколько дней назад. В целом, он сводился к задаче, которая звучала как: поиск в Excel-файле. Давайте попробуем ее решить? 🙂
Собственно, любой Excel-файл — это некоторое количество строк и колонок. Работаем, как всегда — с помощью библиотеки Openpyxl, а для работы с каждой отдельной ячейкой — используем цикл while.
В целом, алгоритм работы кода сводится к:
1. Открываем файл (об этом я писал ранее)
2. Читаем первую ячейку в строке
3. Переходим к следующей строке в этом столбце
4. После того, как достигли максимума по количеству ячеек в столбце — переходим к следующему столбцу.
5. И так до полной обработки файла.
Важно: для того, что бы цикл работал — нам нужно знать количество ячеек в строках и в столбцах. Для этого используем конструкции в виде:
-
row_max = sheet_active.max_row # Получаем количество столбцов
и
-
column_max = sheet_active.max_column # Получаем количество строк
Сам код с комментариями — доступен ниже.
-
import openpyxl
-
from openpyxl.utils import get_column_letter
-
import re
-
-
path_to_file = 'base_to_search.xlsx'
-
-
search_text = input(str('Какой текст ищем: '))
-
search_text = search_text.lower()
-
print('Ищем:', search_text)
-
-
wb = openpyxl.load_workbook(path_to_file) # Грузим наш прайс-лист
-
sheets_list = wb.sheetnames # Получаем список всех листов в файле
-
sheet_active = wb[sheets_list[0]] # Начинаем работать с самым первым
-
row_max = sheet_active.max_row # Получаем количество столбцов
-
#print(type(row_max))
-
column_max = sheet_active.max_column # Получаем количество строк
-
-
print('В файле:', path_to_file, 'n Cтолбцов:', row_max, 'n Колонок:', column_max)
-
-
row_min = 1 #Переменная, отвечающая за номер строки
-
column_min = 1 #Переменная, отвечающая за номер столбца
-
-
while column_min <= column_max:
-
row_min_min = row_min
-
row_max_max = row_max
-
while row_min_min <= row_max_max:
-
row_min_min = str(row_min_min)
-
-
word_column = get_column_letter(column_min)
-
word_column = str(word_column)
-
word_cell = word_column + row_min_min
-
-
data_from_cell = sheet_active[word_cell].value
-
data_from_cell = str(data_from_cell)
-
#print(data_from_cell)
-
regular = search_text
-
result = re.findall(regular, data_from_cell)
-
if len(result) > 0:
-
print('Нашли в ячейке:', word_cell)
-
row_min_min = int(row_min_min)
-
row_min_min = row_min_min + 1
-
column_min = column_min + 1
Конечно, я буду рад любым комментариям и вопросам. Для этого используйте почту или Telegram.
Больше …
Самое основное, с чего начинается изучение языка — с фраз…
Устали фильтровать данные в excel?
Есть решение, как с помощью Python осуществить поиск строк в файле по ключевым словам в столбцах.
Несомненно, многие из нас в своей работе не раз сталкивались с необходимостью фильтрации данных в файле excel, обычно мы делаем это через встроенный в программу фильтр, но бывают ситуации, когда нужно осуществить отбор строк по большому количеству условий (в нашем случае – по ключевым словам) сразу по нескольким столбцам.
Рассмотрим задачу более подробно. Например, у нас есть файл excel с обращениями клиентов в банк (тысячи строк), который содержит следующие колонки: «ИНН клиента», «Дата обращения», «Обращение», «Решение». В столбце «Обращение» содержится текст обращения клиента, в столбце «Решение» — ответ банка на обращение. Суть обращений может быть абсолютно любой (кредитование, страхование, эквайринг и т.д).
Требуется с помощью поиска ключевых слов/сочетаний слов (например, «КАСКО», «ОСАГО», «автострахов», «залог…авто» и т.п.) в колонках «Обращение» и «Решение» выбрать обращения клиентов, которые относятся к страхованию автотранспорта. Нужные слова могут содержаться как в обоих столбцах, так и в одном из них.
Конечно, можно начать фильтровать данные колонки в excel, но это будет долго и трудоёмко, особенно, если слов для поиска подходящих обращений много (или столбцов, в которых необходимо найти ключевые слова). Поэтому для решения нашей задачи требуется более удобный инструмент – Python.
Ниже представлен код, с помощью которого мы отберем необходимые обращения клиентов:
# Импорт библиотек.
import pandas as pd
import numpy as np
import re
#Чтение исходного файла с данными.
df = pd.read_excel(r’ПУТЬ К ФАЙЛУНазвание исходного файла с данными.xlsx’, dtype=’str’)
# Регулярные выражения.
# Шаблон (слова/сочетания слов, которые необходимо найти в столбцах).
r = r'(каско)|(осаго)|(страх.*?транспорт)|(транспорт.*?страх)|(страх.*?авто)|(авто.*?страх)|(залог.*?транспорт)|(транспорт.*?залог)|(залог.*?авто)|(авто.*?залог)|(автострахов)’
Поясним, что «.*?» в выражении (страх.*?транспорт) ищет между «страх» и «транспорт» любое количество символов, вопросительный знак отключает жадность алгоритма поиска (поиск заканчивается как только находится первый «транспорт»).
#Для каждой строки ищем шаблон в столбце «Обращение».
obr = df[‘Обращение’].apply(lambda x: re.search(r, str(x).lower())) #другой вариант: obr = df[‘ Обращение ‘].str.lower().str.contains(r)
#Для каждой строки ищем шаблон в столбце «Решение».
otvet = df[‘Решение’].apply(lambda x: re.search(r, str(x).lower())) #другой вариант: otvet = df[‘Решение’].str.lower().str.contains(r)
#Для каждой строки проверяем наличие шаблона хотя бы в одном из столбцов «Обращение» и «Решение» (результат — True/False).
itog = np.any(np.array([~obr.isnull(), ~otvet.isnull()]), axis=0)
#Результат (оставляем только те строки в таблице, по которым получен результат True).
new_df = df[itog]
#Запись результата в excel.
new_df.to_excel(‘Название итогового файла.xlsx’, index=False)
В результате получаем новый файл excel, в который полностью скопированы нужные нам обращения клиентов:
— в обращении клиента с ИНН 1111111111 в столбцах «Обращение» и «Решение» содержится слово «КАСКО»;
— в обращении клиента с ИНН 333333333333 в столбце «Решение» содержатся сочетания слов «залог…транспорт», «транспорт…страх», «залог…авто», «страх…авто»;
— в обращении клиента с ИНН 444444444444 в столбце «Обращение» содержатся сочетания слов «страх…транспорт»; «транспорт…залог».
Количество столбцов, в которых можно производить поиск ключевых слов, не ограничен – в приведенном примере их два, но у вас может быть больше.
При необходимости для каждого столбца можно задать свой шаблон для поиска слов:
#Шаблон 1 для столбца «Обращение».
r1= r'(каско)|(осаго)|(страх.*?транспорт)|(транспорт.*?страх)|(страх.*?авто)|(авто.*?страх)’
#Шаблон 2 для столбца «Решение».
r2= r'(залог.*?транспорт)|(транспорт.*?залог)|(залог.*?авто)|(авто.*?залог)|(автострахов)’
#Поиск шаблонов 1 и 2 в столбцах «Обращение» и «Решение» соответственно.
obr = df[‘Обращение’].apply(lambda x: re.search(r1, str(x).lower()))
otvet = df[‘Решение’].apply(lambda x: re.search(r2, str(x).lower()))
Если требуется выбрать строки, в которых ключевые слова содержатся и в том, и в другом столбце, то нужно заменить функцию any() на all():
itog = np.all(np.array([~obr.isnull(), ~otvet.isnull()]), axis=0)
Теперь рассмотрим ситуацию, когда у нас имеется несколько файлов excel с обращениями клиентов (с аналогичной структурой столбцов), и необходимо в каждом выбрать подходящие обращения.
Тогда код, с помощью которого мы отберем нужные строки, будет выглядеть так:
#Импорт библиотек.
import pandas as pd
import numpy as np
import os
import re
import warnings
#Игнорирование всех предупреждений.
warnings.filterwarnings(‘ignore’)
#Путь к папке с исходными файлами.
path = r’ПУТЬ К ПАПКЕ С ФАЙЛАМИ ‘
#Регулярные выражения.
#Шаблон (слова/сочетания слов, которые необходимо найти в столбцах).
r= r'(каско)|(осаго)|(страх.*?транспорт)|(транспорт.*?страх)|(страх.*?авто)|(авто.*?страх)|(залог.*?транспорт)|(транспорт.*?залог)|(залог.*?авто)|(авто.*?залог)|(автострахов)’
#Создание папки, в которую будут сохраняться файлы с нужными обращениями.
os.makedirs(‘Нужные обращения’, exist_ok=True)
#Получение списка полных имён для всех файлов xlsx в папке с исходными файлами.
docs = []
for root, _, files in os.walk(path):
for file in files:
if file.split(‘.’)[-1] == ‘xlsx’:
docs.append(os.path.join(root, file))
print(f’В директории {path} nобнаружено {len(docs)} файлов’)
#Для каждого файла из списка производим его чтение, поиск шаблона в столбцах «Обращение» и «Решение», проверяем наличие шаблона хотя бы в одном из данных столбцов, оставляем только те строки в таблице, по которым получен результат True, записываем результат в excel в папку «Нужные обращения».
%%time
for i, doc in enumerate(docs):
df = pd.read_excel(doc)
print(f'{i+1} файл из {len(docs)} прочитан’, end=’ ‘)
obr = df[‘Обращение’].apply(lambda x: re.search(r, str(x).lower()))
otvet = df[‘Решение’].apply(lambda x: re.search(r, str(x).lower()))
itog = np.any(np.array([~obr.isnull(), ~otvet.isnull()]), axis=0)
df = df[itog]
df.to_excel(os.path.join(‘Нужные обращения’, doc.split(‘\’)[-1]), index=False)
print(‘и обработан’)
В результате создается папка «Нужные обращения», в которой содержатся новые файлы excel с полностью скопированными нужными обращениями клиентов. По количеству и названию данные файлы соответствуют исходным.
Таким образом, благодаря Python поиск строк в файлах по ключевым словам в столбцах становится быстрым и несложным делом. Приведенный код значительно ускоряет и упрощает работу аналитика в части фильтрации строк по большому количеству условий по нескольким столбцам.
I have an excel sheet (data.xlxs) with the following pattern of data with more than 200 rows.
NS71282379_67698209 123456001
NS71282379_56698765 123456002
NS71282379_67698209 123456003
.
.
.
Now in my script, I am trying to find the corresponding value for 123456003
as NS71282379_67698209
. In my script, I want to replace 123456003 with its value from the excel sheet.
I used xlrd
to import the sheet but haven’t found any method which easily allows me to find the corresponding value.
How can I do this smartly?
ballade4op52
2,2374 gold badges25 silver badges41 bronze badges
asked Apr 20, 2016 at 20:51
2
you can iterate the Excel sheet by range(sheet.nrows) and get row values based on the row number. The script below iterates the Excel sheet row by row and prints out the row that matches value 123456003. You can modify it to meet your requirement
$cat test.py
import xlrd
def open_file(path):
wb = xlrd.open_workbook(path)
sheet = wb.sheet_by_index(0)
for row_num in range(sheet.nrows):
row_value = sheet.row_values(row_num)
if row_value[1] == 123456003:
print row_value
if __name__ == "__main__":
path = "data.xlsx"
open_file(path)
$python test.py
[u'NS71282379_67698209', 123456003.0]
ballade4op52
2,2374 gold badges25 silver badges41 bronze badges
answered Apr 20, 2016 at 21:20
Haifeng ZhangHaifeng Zhang
29.5k19 gold badges77 silver badges124 bronze badges
You will have to iterate over the rows and find the one you’re interested in changing. Something like this:
for r in xrange(sheet.nrows):
row = sheet.row(r)
if row[0].value == "NS71282379_67698209":
row[1].value = "new value"
break
If you need to do this repeatedly, you could instead build a map from the first column values to the second column cells:
cells = dict((row[0].value, row[1])
for row in (sheet.row(r) for r in xrange(sheet.nrows)))
cells["NS71282379_67698209"].value = "new value"
answered Apr 20, 2016 at 21:25
Last updated on
Feb 10, 2022
Do you need to search and replace a list of values in a big Excel file with many sheets?
If so, I’ll show you the steps to search in Excel file — list of words and replace them. In this article you can find the exact cell(with packages like xlrd, xlwt and openpyxl) and partial cell match. At the end a new Excel file is generated with the replaced values.
Let’s check the example data:
A | B | C |
---|---|---|
4321 | 3210 | 2100 |
1 | 0 | 0 |
2 | 1 | 0 |
3 | 2 | 1 |
4 | 3 | 2 |
we are going to search for 0 and 1 — and replace them with False and True.
A | B | C |
---|---|---|
4321 | 3210 | 2100 |
True | False | False |
2 | True | False |
3 | 2 | True |
4 | 3 | 2 |
You can check also this video:
Easily extract information from Excel with Python and Pandas
Python and Excel — search and replace with xlrd and xlwt
In this example we are going to use two Python packages: xlrd
and xlwt
.
Step 1: Read Excel file
The first package reads the Excel file and a given sheet by name or index:
import xlwt
import xlrd
# read Excel file and sheet by name
workbook = xlrd.open_workbook('/home/vanx/Documents/example1.xlsx')
sheet = workbook.sheet_by_name('Test')
sheet2 = workbook.sheet_by_index(2)
Step 2: Create new Excel file
The second package — xlwt
— will be used to write the data into new Excel file:
new_workbook = xlwt.Workbook()
new_sheet = new_workbook.add_sheet('Test')
Step 3: Search and replace a cell in xlsx file
The next step is to define replacement pairs like: {1:True, 0:False}
:
replacement = {1:True, 0:False}
Step 4: Search and replace a cell in xlsx file
Finally the code iterates over the rows and columns is controlled by:
ncols
— number of columns in the selected sheetnrows
— number of rows in the selected sheet
This is the final part of the code:
# iterate over the rows
for i in range(sheet.nrows):
print(i)
data = [sheet.cell_value(i, col) for col in range(sheet.ncols)]
for index, value in enumerate(data):
if value in replacement.keys():
new_sheet.write(i, index, str(replacement.get(value)))
else:
new_sheet.write(i, index, value)
new_workbook.save('example.xls')
where new_workbook.save('example.xlsx')
saves the data into file — example.xlsx
Python and Excel — search and replace with openpyxl
Another Python package exists and can be used — openpyxl
. It can do the same as the previous example. Difference is that only one module is used for reading and writing new Excel file:
import openpyxl
from openpyxl.utils.cell import get_column_letter
wb = openpyxl.load_workbook('/home/vanx/Documents/example1.xlsx')
wb.sheetnames
sheet = wb["Test"]
number_rows = sheet.max_row
number_columns = sheet.max_column
replacement = {'1':True, '0':False}
for i in range(number_columns):
for k in range(number_rows):
cell = str(sheet[get_column_letter(i+1)+str(k+1)].value)
for key in replacement.keys():
if str(cell) == key:
newCell = replacement.get(key)
sheet[get_column_letter(i+1)+str(k+1)] = str(newCell)
wb.save('example1.xlsx')
The code above reads file: example1.xlsx
from folder ~/Documents
and then produces a new Excel file in the current working directory. In the file there are several sheets — we are interested in the one named — Test
.
Getting the number of rows and columns is done by:
sheet.max_row
sheet.max_column
Finally we iterate and search for the values. In case of a match then we will replace the cell with the new values.
Python and Excel — partial match
The previous examples work with exact text matches for the cell value. If you need to perform partial match than you can try with Python code like:
if str(cell[0]) == key:
This will search only the first character of the cell if it’s exactly the searched value.
Or if the cell contains the key:
if key in str(cell[0]):
Regex can be used as well. The problem for such partial matches is performance — it might take resources and time for large Excel files.
Working with Python and Excel together is really fun for a VBA Developer! It somehow shows you what all these years of coding with VBA have taught you! Today, I was thinking how to implement the .Find() method of searching in Excel values.
At first, I have tought about going old school and simply loop through all the cells in a given Excel range, check their values and thus implement a “manual” search. For this, I have generated an Excel file with the xlswriter library and I have read it with the xlrd library. Both are quite easy to be used, if you are aware how the Excel object model is built.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import xlsxwriter from xlsxwriter.utility import xl_rowcol_to_cell import xlrd #First part of the code, used only to create some Excel file with data wbk = xlsxwriter.Workbook(‘hello.xlsx’) wks = wbk.add_worksheet() i = —1 for x in range(1, 1000, 11): i+=1 cella = xl_rowcol_to_cell(i, 0) #0,0 is A1! cellb = xl_rowcol_to_cell(i, 1) cellc = xl_rowcol_to_cell(i, 2) #print (cella) wks.write(cella,x) wks.write(cellb,x*3) wks.write(cellc,x*4.5) myPath= r‘C:Desktophello.xlsx’ wbk.close() #SecondPart of the code for sh in xlrd.open_workbook(myPath).sheets(): for row in range(sh.nrows): for col in range(sh.ncols): myCell = sh.cell(row, col) print(myCell) if myCell.value == 300.0: print(‘————‘) print(‘Found!’) print(xl_rowcol_to_cell(row,col)) quit() |
This is the generated excel file from the first part of the code. (Does it remind something from here?):
This is what Python prints, which is actually quite nice:
Secondly, I remembered that I have actually learnt programming in Python some years ago and this is a programming blog, thus I should probably not code as a first year student (or so). Thus, I have decided to introduce at least one function. So, the function was named findCell and I have rewritten my code to this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import xlsxwriter import os import xlrd import time from xlsxwriter.utility import xl_rowcol_to_cell def findCell(sh, searchedValue): for row in range(sh.nrows): for col in range(sh.ncols): myCell = sh.cell(row, col) if myCell.value == searchedValue: return xl_rowcol_to_cell(row, col) return —1 myName = ‘hello.xlsx’ wbk = xlsxwriter.Workbook(myName) wks = wbk.add_worksheet() i = —1 for x in range(1, 1000, 11): i+=1 cella = xl_rowcol_to_cell(i, 0) #0,0 is A1! cellb = xl_rowcol_to_cell(i, 1) cellc = xl_rowcol_to_cell(i, 2) wks.write(cella,x) wks.write(cellb,x*3) wks.write(cellc,x*4.5) myPath= os.getcwd()+«\»+myName searchedValue = 300 for sh in xlrd.open_workbook(myPath).sheets(): print(findCell(sh, searchedValue)) input(‘Press ENTER to exit’) |
Now, it is a bit fancier, as the code could be executed with a click. On the previous one, I have written quit() , thus one should execute it from the console. Still, B10 is found:
Thirdly, I have read a comment from @ashleedawg, that one should be able to use the Excel API and thus use the Find() method from it. The whole programming becomes quite easy this way, using the xlwings library:
import xlwings as xw bookName = r‘C:somePathhello.xlsx’ sheetName = ‘Sheet1’ wb = xw.Book(bookName) sht = wb.sheets[sheetName] myCell = wb.sheets[sheetName].api.UsedRange.Find(‘test’) print(‘—————‘) print (myCell.address) input() |
Thus, from an imput like this:
I was still able to get the A10:
That’s all folks! All the code is in GitHub here – Python Find.
-
xlrd documentation
-
xlswriter documentation
-
xlwings documentation