본문 바로가기
Coding(코딩)/Python

[Python] 텍스트 파일 읽고 쓰고 대체하기 - pandas 라이브러리 활용

by DevKev 2023. 5. 9.

To Do

파일 읽기

✅ 파일 쓰기

✅ 파일 내 텍스트 대체하기

 

내가 주로 해왔던 파라메트릭 모델링을 하기 위해서는 위의 작업을 수행할 줄 알아야 하는데, 특히 개인적으로는 텍스트 대체가 must인 것 같다. 기본적인 파일 읽고 쓰는 것부터 기존의 텍스트를 대체하여 삽입하는 것까지 이번 포스트에서 다뤄본다. 간단한 경로 접근과 파일명 관련해서 스트링(str) 슬라이싱도 일부 포함한다.

 

설명하면서 드는 예시는 내가 작업했던 FEM 해석 소프트웨어 아바쿠스(ABAQUS) .inp 파일을 읽고 관련 텍스트 파일을 수정하는 과정을 서술했다. 그냥 확장자만 다른 텍스트 파일이라 텍스트 파일 읽기, 쓰기, 수정에 관한 내용에 알고 싶어서 보고 있다면, 읽어봐도 무방하다.

 

 

 

 

 

 

 

 

 

 

 

파일 읽고 쓰기(read & write)

파일을 읽고 쓰는데에는 이 포스트에서 다루는 리소스 한정 두 가지 방법이 있을 수 있다. 간단하게 분류하자면 판다스(pandas) 라이브러리의 활용 여부에 따라 나뉜다. 즉, w/ & w/o Pandas 라이브러리. 그 두가지 방법을 모두 다뤄본다.

 

- OS 모듈 활용

OS 모듈을 활용하면 쓰게되는 함수는 다음과 같다.

  • os.open
  • os.write
  • os.close 

os.open의 경우 method/mode가 여섯가지 인데 다음 표와 같다:

'r' Read Only: 읽기 전용
'r+' Read and Write: 읽기/쓰기
'w' Write Only: 기존의 텍스트 수정 or 덮어씀 
'w+' Write and Read: 기존 텍스트 삭제 or 덮어씀 
'a' Append Only : 기존 텍스트 끝(end)에 추가됨
'a+' Append and Read: a와 동일

 

- Pandas 패키지 활용

Pandas 패키지를 활용한다면 다음과 같은 함수를 활용한다.

import pandas as pd

#파일 읽기
pd.read_csv('파일명', sep='한정자 type', header='헤더 여부') # Delimiter(한정자)가 있는 경우
pd.read_fwf('파일명') # 그냥 텍스트 파일

#pandas dataframe 예시
df = pd.DataFrame(변수명)

#파일 쓰기
df.to_csv('파일명')

간단한 설명을 마치고 세부적으로 그 예시를 알아보자.

 

이번 예제에서는 아래의 예제 파일을 읽고 쓰려고 한다.

초반에 언급했지만 반복하면, '.inp' 파일은 확장자만 다르고 동일한 텍스트 파일이다. 

 

[예시 a.inp 파일]

*Heading
** Job name: Job-1 Model name: Job-1
** Generated by: Abaqus/CAE 2021
*Preprint, echo=NO, model=NO, history=NO, contact=NO
**
** PARTS
**
*Part, name=TEST23_INST
*Node
      1,          33.,         241.,           0.
      2,          33.,         241.,         1000
      3,           0.,         244.,         1000
      4,           0.,         244.,           0.
      5,          35.,         251.,         1000
      6,           0.,         250.,         1000
*Element, type=C3D8
** MATERIALS
**
*Material, name=A
*Elastic
200000., 0.3
*Plastic
300., 0.
**
** BOUNDARY CONDITIONS

 

 

 

[ 파일 읽기 - Read files ]

- OS 모듈 활용

위에서 정리한 'r' 속성으로 텍스트 파일을 읽으면 된다. 그냥 텍스트를 읽는 것 자체는 매우 간단하다. 다음의 과정을 참고하자. 줄 별로 읽기 때문에 제대로 읽었는지 확인하려고 출력해봤고 제대로 읽어들인다.

import os

#파일 읽기 - a.inp는 .py와 동일한 폴더 내에 존재
f = open('a.inp', mode='r')

#제대로 읽었는지 확인
for line in f:
	print (line)

 

- Pandas 패키지 활용

마찬가지로 pandas를 이용해도 한 두줄이면 끝난다.

import pandas as pd

#Pandas로 파일 읽기
dat = pd.read_fwf('a.inp')

#읽은 파일 출력
print (dat)

 

[ 파일 쓰기 - Write files ]

a.inp로 덮어 쓰는게 아닌 다른 파일로 출력을 진행하려고 한다. 출력 대상이 현재 존재하지 않는 파일이어도 파일이 생성이 된다.

 

- OS 모듈 활용

작성할 때 유의 할 점은 다음과 같다:

  • f.write(스트링)
  • open() 했으면 close() 해주기
import os
text = {'x': 10, 'y': 20, 'z': 30}
f = open('b.inp', mode='w')
f.write(str(text))
f.close()

 

- Pandas 패키지 활용

위보다 간단하다. 그냥 데이터프레임으로 변환해주고, 데이터프레임의 to_csv로 파일 output이 가능.

import pandas as pd

#예시 데이터 Pandas 데이터프레임으로 변환 
text = pd.DataFrame({'x': [10], 'y': [20], 'z': [30]})

#b.inp 파일로 output
text.to_csv('b.inp', index=False)

 

 

 

텍스트 삽입(insert)

위에서 파일을 읽고 쓰는 과정을 간단하게 다뤄봤고 본격적으로 이 포스트의 목적인 텍스트 삽입에 대해서 알아보자. 삽입이라는게 결국에는 읽고 쓰는게 동시에 이루어지는 작업이다.

 

위의 예시 파일에서 *Node에 해당하는 텍스트만 바꾸고 싶다. 그 아래는 요소(element), 재료(material), 경계 조건(boundary conditions) 관련 내용인데 알 필요 없고 이번 예시는 그냥 해당 노드의 좌표(coordinate)만 원하는 텍스트로 대체하는 과정이다.

 

과정을 정리하면 다음과 같다:

  1. *Node 전 까지 읽는다.
  2. *Element 부터 끝까지 읽는다.
  3. *Node 부터 *Element 전까지는 내가 원하는 텍스트로 대체한다.

그럼 이제부터는 위에서 사용했던 방법들을 적절하게 섞어서 내가 원하는 결과를 얻어내는 과정을 보자. 먼저 남기기를 원하는 부분을 나눠(split)줘야 한다. 다음의 코드에서 위의 항목 중 1번, 2번을 수행한다. 텍스트 파일 용량이 크다면 찾아보니 효율적인 방법은 아닌 듯하다. 아래처럼 with 문을 쓰게 되면 앞서 말했던 close()가 따로 필요없는 것 또한 참고하자.

 

import os

with open('a.inp') as f:
    contents = f.read()
    char1 = '*Node'
    spl_res1 = contents.split(char1)
    char2 = '*Element, type=C3D8'
    result = spl_res1[1].split(char2)

 

내가 원하는 텍스트는 다음의 변수에 할당이 된다.
*Node 전: spl_res1[0]

*Element 부터 끝: result[1]

 

여러 번 이 작업을 반복해야한다면 내가 원하는 텍스트를 그냥 단순히 각각 다른 텍스트 파일에 담아서 이어 붙이는게 불필요한 연산을 줄일 수 있을 것 같은데 그 부분은 스킵하자.

 

그럼 마지막으로 내가 원하는 텍스트를 사이에 삽입하는 일만 남았다. b.inp에 다음과 같이 작성되어 있고 이를 삽입할 것이다.

      1,          33222.,         241.,           0.
      2,          3333.,         241.,         2000
      3,           0.,         244.,         1000
      4,           0.,         244.,           0.
      5,          3777.,         251.,         2000
      6,           0.,         250.,         1000
      7,          3777.,         251.,         2000
      8,           0.,         250.,         1000
      9,          3777.,         251.,         2000
      10,           0.,         250.,         1000

 

최종적인 코드는 다음과 같다:

import os

with open('a.inp') as f:
    contents = f.read()
    char1 = '*Node'
    spl_res1 = contents.split(char1)
    char2 = '*Element, type=C3D8'
    result = spl_res1[1].split(char2)

with open('b.inp') as f:
    contents = f.read()

with open('c.inp', 'w') as f:
    f.write('{0}\n'.format(spl_res1[0]))
    f.write('{0}\n'.format(char1))
    f.write('{0}\n'.format(contents))
    f.write('{0}\n'.format(char2))
    f.write('{0}\n'.format(result[1]))

 

정상적으로 원하는 텍스트가 삽입되었고, 출력된 c.inp 결과물은 다음과 같다:

textfile output result
[ 출력된 c.inp 텍스트 파일 ]

 

ChatGPT는 어떻게 짤까?

갑자기 챗 지피티는 관련해서 어떻게 코드를 제안할지 궁금해졌고, 마지막으로 챗 지피티가 제안하는 코드를 돌려보면서 마무리를 해보겠다. 지인들한테 들어보니 자기가 짠 지저분한 코드를 그렇게 정리를 간단하게 해준다고 해서 나도 해본다.

 

To insert text at a specific position in an existing text file, you can use Python's fileinput module. Here's an example:
import fileinput

# Open the file in read mode
with open('filename.txt', 'r') as file:
    # Read the file contents into a list of lines
    lines = file.readlines()

# Insert a new line of text at line number 3 (index 2 in the list)
lines.insert(2, 'This is a new line\n')

# Open the file in write mode and write the modified list of lines
with open('filename.txt', 'w') as file:
    file.writelines(lines)
In this example, we first open the file in read mode and read its contents into a list of lines using the readlines() method. We then insert a new line of text at a specific position in the list using the insert() method. Finally, we open the file in write mode and write the modified list of lines back to the file using the writelines() method.

Note that in this example we're inserting the new line of text at position 3 (index 2) in the list. You can modify this to insert the new line at any other position by changing the index value accordingly.

 

코드를 작성하는 방법에는 무수히 많은 방법이 있을 수 있기 때문에 자기 스타일에 맞게 그리고 효율적으로 짜는게 어려울 때 가끔 도움을 받으면 좋을 것 같다. 앞으로 코드를 작성할 때 도움을 조금 얻어보는 버릇(?)도 들여봐야겠다. 도움이 되길 바라며...