web-dev-qa-db-ja.com

openpyxlでフィールド名または列ヘッダーを使用する方法

以下の私のコードを参照してください。このコードは非常にうまく機能しますが、2つのことを行いたいと思います。たとえば、実際の文と比べて、またはそれよりもはるかに短い文を作成した場合です。私はこのような列をたくさん持っていますが、すべてが隣り合っているわけではありません。もっと短くしてほしい。また、正確な列文字がわからない場合もあります。

したがって、列名またはヘッダーを知る方法があるかどうかを知りたいです。一番上の行にある値のように。そのため、指定した列にある場合、常にそのセルで機能を実行するための値の1つであるかどうかをテストできます。列名を実行するopenpyxl関数が見つかりません。最初の行が残りの行と異なることを理解しているかどうかはわかりません。おそらく最初の行でテストを試すことはできると思いますが、これを行う方法がわかりません。

それで、列名を呼び出す方法はありますか?または、列名を呼び出してテストする方法がない場合、誰かが最初の行をチェックして値があるかどうかを確認するのを手伝ってくれる?次に、私がいる正しい行で変更しますか?これは理にかなっていますか。

したがって、コードの代わりに:

if cellObj.column == 'H' or ...

それは言うでしょう:

if cellObj.column_header == 'NameOfField or ...

またはそれができない場合は、次のようにします。

if this cell has column where first row value is 'NameOfField' ...

これを行う最善の方法を手伝ってください。私はスタックオーバーフローと本とブログサイトを見てきましたが、列名を呼び出す方法ではないようです(列の文字ではありません)。

for row in sheet.iter_rows():
 for cellObj in row:
    if cellObj.column == 'H' or cellObj.column == 'I' or cellObj.column == 'L' or cellObj.column == 'M':
        print(cellObj.value),
        if cellObj.value.upper() == 'OldValue1':
            cellObj.value = 1
            print(cellObj.value)
        Elif cellObj.value.upper() == 'OldValue2':
            cellObj.value = 2
            print(cellObj.value)
8
stahna

[〜#〜]編集[〜#〜]

これらがあなたが探しているヘッダー名であると仮定します:

colnames = ['Header1', 'Header2', 'Header3']

これらの列のインデックスを見つけます。

col_indices = {n for n, cell in enumerate(sheet.rows[0]) if cell.value in colnames}

残りの行を繰り返します。

for row in sheet.rows[1:]:
    for index, cell in enumerate(row):
         if index in col_indices:
             if cell.value.upper() == 'OldValue1':
                  cell.value = 1
                  print(cell.value)
             Elif cell.value.upper() == 'OldValue2':
                 cell.value = 2
                 print(cell.value)

列名を維持するために、セットではなく辞書を使用します。

col_indices = {n: cell.value for n, cell in enumerate(sheet.rows[0]) 
               if cell.value in colnames}

for row in sheet.rows[1:]:
    for index, cell in enumerate(row):
        if index in col_indices:
            print('col: {}, row: {}, content: {}'.format(
                   col_indices[index], index, cell.value))
            if cell.value.upper() == 'OldValue1':
                 cell.value = 1
            Elif cell.value.upper() == 'OldValue2':
                 cell.value = 2

古い答え

これにより、ifステートメントが短くなります。

if cellObj.column in 'HILM':
    print(cellObj.value),

複数文字の列座標の場合は、リストを使用する必要があります。

if cellObj.column in ['H', 'AA', 'AB', 'AD']:
    print(cellObj.value),
5
Mike Müller

Sheet.cell(row =#、column =#)構文を使用して、最初の行と列からセルにアクセスできます。例えば:

for row in enumerate(sheet.iter_rows()):
    for j, cellObj in enumerate(row):
        header_cell = sheet.cell(row=1, column=j)

        if cellObj.column in ['H', 'I', 'L', 'M', 'AA', 'AB']:
            print(cellObj.value),
            if cellObj.value.upper() == 'OldValue1':
                cellObj.value = 1
                print(cellObj.value)
            Elif cellObj.value.upper() == 'OldValue2':
                cellObj.value = 2
                print(cellObj.value)
1
tornesi

rowはジェネレーターを返すため、最初の反復でヘッダーを簡単に抽出し、必要に応じてヘッダーを処理してから、引き続き使用できます。例えば:

headers = [cell.value for cell in next(sheet.rows)]
# find indexes of targeted columns
cols = [headers.index(header) for header in 'HILM']

conv = {'OldValue1': 1, 'OldValue2': 2}

for row in sheet.rows:
    values = [cell.value for cell in row]
    for col in cols:
        values[col] = conv[values[col]] 
0
Nuno André

これには多くの方法があります。私が使用したいくつかのアプローチ:

1。ブルートフォース

「シート」と「ワークブック」が定義されていると仮定します。

header = [cell for cell in sheet['A1:XFD1'][0] if cell.value is not None and cell.value.strip() != ''] #you get all non-null columns
target_values = ['NameOfField', 'NameOfField1', 'NameOfField2'] #filter list
target_header = [cell.column for cell in header if cell.value in target_values] #get column index

data = {'OldValue1': 1, 'OldValue2': 2}

for row in sheet.iter_rows(max_row=sheet.max_row, max_col=sheet.max_column):
 for cell in row:
     if cell.column in target_header and cell.value in data :
         cell.value = data[cell.value]

この場合、ブルートフォースは "sheet ['A1:XFD1']"にあります。最初にすべての列をチェックする必要があります。しかし、列のすべてのセル参照を取得します。その後、target_values(列名...)を作成し、列インデックス(のリストを作成しますtarget_header)。最後に、シートを反復しました。セルの列が列インデックスにあるかどうかをチェックし、セルの値がデータにあるかどうかをチェックするので、値を変更できます。

Downside:「データ領域」の外側にランダムな空白があるセルが存在する場合。 max_rowとmax_columnは、そのセル(空白のセルを繰り返す)を考慮します。

2。境界をチェックしてください

データにテーブルフォームがある場合は、独自の最大行と最大列を使用できます(列間に空白スペース、 "id"のある列-> nullではなく、空白ではありません)

from openpyxl.utils import get_column_letter 

def find_limit_sheet(direction):
    max_limit_value = 1
    while (direction(max_limit_value).value is not None) and (direction(max_limit_value).value.strip() != ''):
        max_limit_value = max_limit_value + 1
    return (max_limit_value - 1) if max_limit_value != 1 else 1


max_qrow = find_limit_sheet(direction=lambda increment: sheet.cell(row=increment, column=1))
max_qcolumn = find_limit_sheet(direction=lambda increment: sheet.cell(column=increment, row=1))

header = [cell for cell in sheet[f'A1:{get_column_letter(max_qcolumn)}1']] #you get all non-null columns
target_values = ['NameOfField', 'NameOfField1', 'NameOfField2'] #filter list
target_header = [cell.column for cell in header[0] if cell.value in target_values] #get column names

data = {'OldValue1': 1, 'OldValue2': 2}

for row in sheet.iter_rows(max_row=max_qrow, max_col=max_qcolumn):
 for cell in row:
     if cell.column in target_header and cell.value in data :
         cell.value = data[cell.value]

この場合、「データ領域」内のみにいます。

3。オプション:パンダの使用

Excelデータでより複雑な操作が必要な場合(私は自分の作業で大量のExcelを読み取る必要があります:(データソースとして)。pandas dataframe-> make operation-> save結果.

この場合、すべてのデータを使用します。

from openpyxl.utils import get_column_letter 
import pandas as pd

def find_limit_sheet(direction):
    max_limit_value = 1
    while (direction(max_limit_value).value is not None) and (direction(max_limit_value).value.strip() != ''):
        max_limit_value = max_limit_value + 1
    return (max_limit_value - 1) if max_limit_value != 1 else 1


max_qrow = find_limit_sheet(direction=lambda increment: sheet.cell(row=increment, column=1))
max_qcolumn = find_limit_sheet(direction=lambda increment: sheet.cell(column=increment, row=1))

header = [cell.value for cell in sheet[f'A1:{get_column_letter(max_qcolumn)}1'][0]] #you get all non-null columns
raw_data = []
for row in sheet.iter_rows(max_row=max_qrow, max_col=max_qcolumn):
    row_data = [cell.value for cell in row]
    raw_data.append(dict(Zip(header, row_data)))

df = pandas.DataFrame(raw_data)
df.columns = df.iloc[0]
df = df[1:]

たとえば、target_dataを使用して、列のサブセットを使用することもできます(例2)。

...
target_header = [cell.column for cell in header[0] if cell.value in target_values] #get column names
...
raw_data = []
for row in sheet.iter_rows(max_row=max_qrow, max_col=max_qcolumn):
    row_data = [cell.value for cell in row if cell.column in target_header]
    raw_data.append(dict(Zip(header, row_data)))

df = pd.DataFrame(raw_data)
df.columns = df.iloc[0]
df = df[1:]
...

[〜#〜]情報[〜#〜]

0
Edvrsoft