

CSVファイルの情報を書き換えたいです。  
車の情報が並べてあるcsvファイルがあり、ユーザーが買いたい車の番号(x)を選ぶとcsvファイルから購入された車の行が削除されるようにしたいです。csvファイルの中身は以下にペーストしました。一番左にあるのがユーザーが選ぶ番号です。30と31に価格が記入されていませんが、今回のケースでは一番左のインデックス番号しかみないはずなので関係ないかと思います。

pandasなどは使わずデフォルトの機能のみでやりたいです。自分の考えとしては元のcsvファイルにwriteモードを使って特定の行以外は元のデータからコピーして入力できたらなと思いながらコードを書きました。よろしくお願いいたします。

* * *

以下のようなプログラムを作りたいです。

ユーザーがバイヤーかディーラーか選ぶ。

**バイヤーの場合:**

  1. 価格帯を三つの中から選択する
  2. 選ばれた価格帯の車を表示する
  3. 買う車の番号を選ぶ、またはプログラムを終了する
  4. 購入された場合は該当の車を削除する(ここで該当の車を削除してくれず、元のままになります)

**ディーラーの場合:**

  1. ユーザーが車の情報を入力する
  2. ユーザーが入力した情報をファイルに書き込む

**問題点**

エラーは出ないのですが、csvファイルには以下の行のみが残ります。

[code]

    88volvowagon104.3188.8ohcfour11423
    
[/code]

* * *

**対象のCSV**

[code]

    index,company,body-style,wheel-base,length,engine-type,num-of-cylinders,horsepower,average-mileage,price
    0,alfa-romero,convertible,88.6,168.8,dohc,four,111,21,13495
    1,alfa-romero,convertible,88.6,168.8,dohc,four,111,21,16500
    2,alfa-romero,hatchback,94.5,171.2,ohcv,six,154,19,16500
    3,audi,sedan,99.8,176.6,ohc,four,102,24,13950
    4,audi,sedan,99.4,176.6,ohc,five,115,18,17450
    5,audi,sedan,99.8,177.3,ohc,five,110,19,15250
    6,audi,wagon,105.8,192.7,ohc,five,110,19,18920
    9,bmw,sedan,101.2,176.8,ohc,four,101,23,16430
    10,bmw,sedan,101.2,176.8,ohc,four,101,23,16925
    11,bmw,sedan,101.2,176.8,ohc,six,121,21,20970
    13,bmw,sedan,103.5,189,ohc,six,182,16,30760
    14,bmw,sedan,103.5,193.8,ohc,six,182,16,41315
    15,bmw,sedan,110,197,ohc,six,182,15,36880
    16,chevrolet,hatchback,88.4,141.1,l,three,48,47,5151
    17,chevrolet,hatchback,94.5,155.9,ohc,four,70,38,6295
    18,chevrolet,sedan,94.5,158.8,ohc,four,70,38,6575
    19,dodge,hatchback,93.7,157.3,ohc,four,68,31,6377
    20,dodge,hatchback,93.7,157.3,ohc,four,68,31,6229
    27,honda,wagon,96.5,157.1,ohc,four,76,30,7295
    28,honda,sedan,96.5,175.4,ohc,four,101,24,12945
    29,honda,sedan,96.5,169.1,ohc,four,100,25,10345
    30,isuzu,sedan,94.3,170.7,ohc,four,78,24,6785
    31,isuzu,sedan,94.5,155.9,ohc,four,70,38,
    32,isuzu,sedan,94.5,155.9,ohc,four,70,38,
    33,jaguar,sedan,113,199.6,dohc,six,176,15,32250
    34,jaguar,sedan,113,199.6,dohc,six,176,15,35550
    35,jaguar,sedan,102,191.7,ohcv,twelve,262,13,36000
    36,mazda,hatchback,93.1,159.1,ohc,four,68,30,5195
    37,mazda,hatchback,93.1,159.1,ohc,four,68,31,6095
    38,mazda,hatchback,93.1,159.1,ohc,four,68,31,6795
    39,mazda,hatchback,95.3,169,rotor,two,101,17,11845
    43,mazda,sedan,104.9,175,ohc,four,72,31,18344
    44,mercedes-benz,sedan,110,190.9,ohc,five,123,22,25552
    45,mercedes-benz,wagon,110,190.9,ohc,five,123,22,28248
    46,mercedes-benz,sedan,120.9,208.1,ohcv,eight,184,14,40960
    47,mercedes-benz,hardtop,112,199.2,ohcv,eight,184,14,45400
    49,mitsubishi,hatchback,93.7,157.3,ohc,four,68,37,5389
    50,mitsubishi,hatchback,93.7,157.3,ohc,four,68,31,6189
    51,mitsubishi,sedan,96.3,172.4,ohc,four,88,25,6989
    52,mitsubishi,sedan,96.3,172.4,ohc,four,88,25,8189
    53,nissan,sedan,94.5,165.3,ohc,four,55,45,7099
    54,nissan,sedan,94.5,165.3,ohc,four,69,31,6649
    55,nissan,sedan,94.5,165.3,ohc,four,69,31,6849
    56,nissan,wagon,94.5,170.2,ohc,four,69,31,7349
    57,nissan,sedan,100.4,184.6,ohcv,six,152,19,13499
    61,porsche,hardtop,89.5,168.9,ohcf,six,207,17,34028
    62,porsche,convertible,89.5,168.9,ohcf,six,207,17,37028
    63,porsche,hatchback,98.4,175.7,dohcv,eight,288,17,
    66,toyota,hatchback,95.7,158.7,ohc,four,62,35,5348
    67,toyota,hatchback,95.7,158.7,ohc,four,62,31,6338
    68,toyota,hatchback,95.7,158.7,ohc,four,62,31,6488
    69,toyota,wagon,95.7,169.7,ohc,four,62,31,6918
    70,toyota,wagon,95.7,169.7,ohc,four,62,27,7898
    71,toyota,wagon,95.7,169.7,ohc,four,62,27,8778
    79,toyota,wagon,104.5,187.8,dohc,six,156,19,15750
    80,volkswagen,sedan,97.3,171.7,ohc,four,52,37,7775
    81,volkswagen,sedan,97.3,171.7,ohc,four,85,27,7975
    82,volkswagen,sedan,97.3,171.7,ohc,four,52,37,7995
    86,volkswagen,sedan,97.3,171.7,ohc,four,100,26,9995
    87,volvo,sedan,104.3,188.8,ohc,four,114,23,12940
    88,volvo,wagon,104.3,188.8,ohc,four,114,23,13415
    
[/code]

**現状のコード**

[code]

    import csv
    
    options = input("Please enter 1 if you are a buyer and please enter 2 if you are a dealer")
    
    if options == "1":
    
        Range = input("Input 1 if you are looking for a car that costs between $0 to $15000\n"
                      "Input 2 if you are looking for the one costs between $15000 to $30000\n"
                      "Input 3 if you are looking for the one costs more than $30000: ")
        # open the inventory file
        infile = open("Automobile_data.csv", "r")
        # line = infile.readlines()
    
        header = next(infile)
        pricerangeL = 0
        pricerangeH = 15000
        if Range == "2":
            pricerangeL = 15000
            pricerangeH = 30000
        elif Range == "3":
            pricerangeL = 30000
            pricerangeH = 10000000
    
        for line in infile:
            line = line[:-1].split(",")
    
            if line[9] == "":
                continue
    
            elif eval(line[9]) <= pricerangeH and eval(line[9]) >= pricerangeL:
                print(line)
    
        infile.close()
    
    
        x = input("Please enter the number of the car you would like to buy or enter exit: ")
    
        if x == "exit":
             quit()
    
    
        else:
            file = open("Automobile_data.csv", "r")
            lines = file.readlines()
            file.close()
    
    
            outfile = open("Automobile_data.csv", "w")
            size = lines.__len__()
            for i in range(size - 1):
                if i == "x":
                    continue
                else:
                    outfile.write(lines[i])
    
            outfile.close()
    
    elif options == "2":
    
        Index = input("Index:")
        Company = input("Company:")
        BodyStyle = input("Body Style:")
        WheelBase = input("Wheel Base:")
        Length = input("Length:")
        EngineType = input("Engine Type:")
        NumCyl = input("Number of Cylinders:")
        HorsePW = input("Horsepower:")
        AV_mil = input("Average Mileage:")
        Price = input("Price:")
    
        NewCar = [Index, Company, BodyStyle, WheelBase, Length, EngineType, NumCyl, HorsePW, AV_mil, Price]
        with open(r'Automobile_data.csv', 'a') as f:
            writer = csv.writer(f)
            writer.writerow(NewCar)
        f.close()
    
[/code]


CC BY-SA 4.0
2021-10-16T21:04:16.343
83133
2023-12-01T19:03:55.427
2021-10-17T06:13:19.143
3060
48675
question
python python3 csv
CSVファイルから特定の行を削除したい


質問のプログラムの下記部分

[code]

        file = open("Automobile_data.csv", "r")
        lines = file.readlines()
        file.close()
    
        outfile = open("Automobile_data.csv", "w")
        size = lines.__len__()
        for i in range(size - 1):
            if i == "x":
                continue
            else:
                outfile.write(lines[i])
    
    
        outfile.close()
    
[/code]

を次のように修正しては如何でしょう。

[code]

        file = open("Automobile_data.csv", "r")
        lines = file.readlines()
        file.close()
    
        outfile = open("Automobile_data.csv", "w")
        size = lines.__len__()
        for i in range(size - 1):
            lineData = lines[i].split(",") //入力ファイルのi行目をカンマで分割する
            if lineData[0] == x:  // 分割した第１項目(車の番号)と、入力された買いたい車の番号(x)が一致したら、
                continue // その行は書き出さない。
            else:      
                outfile.write(lines[i])  // 買いたい車の番号と一致しない行なので、ファイルに書きだす。
    
        outfile.close() // 最後にファイルを閉じる
    
[/code]


CC BY-SA 4.0
2021-10-17T01:04:52.367
83135
2021-10-17T01:04:52.367
217
83133
answer


④の処理だけでなく色々と見直して以下のようにしてみました。  
主に`####`でコメントした所が修正点です。

[code]

    import csv
    
    #### csvファイルの読み込みは処理にかかわらず最初に行い、2次元リストとして読み込んでおく
    with open('Automobile_data.csv', 'r', newline='') as csvfile:
        header = next(csvfile)
        fulldata = [l for l in csv.reader(csvfile)]
    
    options = input("Please enter 1 if you are a buyer and please enter 2 if you are a dealer")
    
    if options == "1":
    
        Range = input("Input 1 if you are looking for a car that costs between $0 to $15000\n"
                      "Input 2 if you are looking for the one costs between $15000 to $30000\n"
                      "Input 3 if you are looking for the one costs more than $30000: ")
    
        pricerangeL = 0
        pricerangeH = 15000
        if Range == "2":
            pricerangeL = 15000
            pricerangeH = 30000
        elif Range == "3":
            pricerangeL = 30000
            pricerangeH = 10000000
    
        #### 選択された価格帯の車情報を抽出し、そのインデックス番号も別途リスト化する
        selected = [l for l in fulldata if l[9] != '' and int(l[9]) <= pricerangeH and int(l[9]) >= pricerangeL]
        selindex = [l[0] for l in selected]
    
        #### 選択された価格帯の車情報を表示する
        for l in selected:
            print(l)
    
        x = input("Please enter the number of the car you would like to buy or enter exit: ")
    
        if x == "exit":
            quit()
    
        #### 指定されたインデックス番号が選択された価格帯のリストに存在しない時は終了する
        elif x not in selindex:
            print('The car with that number does not exist or is out of range.')
            quit()
    
        else:  #### この部分が④相当の新しい処理
            #### 指定されたインデックス番号の車情報を除いた新しいリストを作成する
            newdata = [l for l in fulldata if l[0] != x]
    
            #### 新しいリスト全体をヘッダーと共にcsvファイルとして書き出す
            with open('Automobile_data.csv', 'w', newline='') as csvfile:
                csvfile.write(header)
                writer = csv.writer(csvfile)
                writer.writerows(newdata)
    
    elif options == "2":
    
        #### csvファイル内情報のすべてのインデックス番号を別途リスト化
        fullindex = [l[0] for l in fulldata]
    
        Index = input("Index:")
    
        #### 既に存在するインデックス番号か判定し、存在するなら終了する
        #### (既存情報を書き変える処理にしてもよいが複雑化するのでこの回答では行わない)
        if Index in fullindex:
            print('That index already exists.')
            quit()
    
        Company = input("Company:")
        BodyStyle = input("Body Style:")
        WheelBase = input("Wheel Base:")
        Length = input("Length:")
        EngineType = input("Engine Type:")
        NumCyl = input("Number of Cylinders:")
        HorsePW = input("Horsepower:")
        AV_mil = input("Average Mileage:")
        Price = input("Price:")
    
        NewCar = [Index, Company, BodyStyle, WheelBase, Length, EngineType, NumCyl, HorsePW, AV_mil, Price]
        with open('Automobile_data.csv', 'a', newline='') as f:
            writer = csv.writer(f)
            writer.writerow(NewCar)
        #### 不要な f.close() は削除
    
[/code]


CC BY-SA 4.0
2021-10-17T01:17:30.030
83136
2021-10-17T01:17:30.030
26370
83133
answer


冗長な部分が多いのと入力値のチェックが為されていないので、全体的に書き直してみました。

[code]

    import sys
    import re
    
    CAR_CSV_FILE = 'Automobile_data.csv'
    
    def user_input(prompt):
      try:
        ret = input(prompt)
      except EOFError:
        print('done', file=sys.stderr)
        sys.exit(0)
      return ret
    
    def user_input_integer(prompt):
      try:
        n = int(user_input(prompt))
      except ValueError as e:
        print(e, file=sys.stderr)
        sys.exit(1)
      return n
    
    def buyer():
      price_range = ((0, 15000), (15000, 30000), (30000, float('inf')))
      p = iter(sum(price_range, ()))
      prange = user_input_integer(f'''
        Input 1 if you are looking for a car that costs between ${next(p)} to ${next(p)}
        Input 2 if you are looking for the one costs between ${next(p)} to ${next(p)}
        Input 3 if you are looking for the one costs more than ${next(p)}
        ? '''.replace('    ', ''))
      if prange < 1 or prange > len(price_range): quit()
      prange -= 1
      with open(CAR_CSV_FILE, 'r') as f:
        car_data = f.readlines()
      for car in car_data[1:]:
        car = car.strip()
        price = car.split(',')[-1].strip()
        try:
          price = int(price)
        except ValueError:
          continue
        if price_range[prange][0] <= price <= price_range[prange][1]:
          print(car)
    
      no = user_input(
        'Please enter the number of the car you would like to buy or enter exit: ')
      if no.strip() == 'exit': quit()
      with open(CAR_CSV_FILE, 'w') as outfile:
        outfile.write(
          ''.join(car for car in car_data if not re.match(rf'^{no},', car)))
    
    def dealer():
      prompts = (
        'Index:', 'Company:', 'Body Style:', 'Wheel Base:', 'Length:',
        'Engine Type:', 'Number of Cylinders:', 'Horsepower:',
        'Average Mileage:', 'Price:')
      new_car = []
      for p in prompts:
        new_car.append(user_input(p))
      with open(CAR_CSV_FILE, 'a') as outfile:
        outfile.write(','.join(new_car))
    
    if __name__ == '__main__':
      prompt = 'Please enter 1 if you are a buyer and please enter 2 if you are a dealer: '
      n = user_input_integer(prompt)
      if n == 1:
        buyer()
      elif n == 2:
        dealer()
    
[/code]


CC BY-SA 4.0
2021-10-17T03:58:04.037
83141
2021-10-17T03:58:04.037
47127
83133
answer


### 処理方法(一例として)

データ投入時

  * CSVファイル中の1行を1ファイルとしてデータを作成する

データ処理時

  * 購入したファイルは削除 
    * もしくは「購入済み」ディレクトリに移動。

成果物作成時

  * 残っているファイルを纏めてCSVファイルを作る

### 留意点

次の操作はアトミック（途切れることのない1つの処理）として実行される必要があります。

  1. 購入対象の存在を確認
  2. 購入処理

対策が取られている（※「対策は取らない」という合意も含む）のであれば、他の回答を参考にしてください。プログラム上で対策するのであれば「python
セマフォ」で調べてください。


CC BY-SA 4.0
2021-10-17T14:30:37.110
83148
2021-10-17T18:23:48.673
2021-10-17T18:23:48.673
48452
48452
83133
answer