파일에 저장된 내용을 파싱해서 변경하려고 합니다

kkb의 이미지

# cat ./test.txt
(생략)
Name = Kim
math = 92
english = 88
science = 90
Name = Lee
math = 92
english = 88
science = 90
Name = Park
math = 92
english = 88
science = 90
(생략)

Lee의 english 점수를 수정하고 싶다면 주로 어떤 방법이 좋을까요?
스크립트, sed, C언어 코드 등 방법에 제한은 없습니다

저는 예를 들어서 english 점수를 수정하는 것은 여러가지 방법으로 구현할 수 있겠는데
학생 이름을 선택해서 english 점수를 수정하는 것이 좀 난감합니다
english에 해당하는 라인이 많으니까요

그리고 학생수와 과목수가 변할 수 있기 때문에 유연한 방법이 필요합니다

shint의 이미지

이름을 먼저 찾고.
해당 english를 찾아도 될거같습니다.

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

cleansugar의 이미지

정규식으로 Name=부터 다음 Name=까지 잘라서 배열에 넣은 다음 다시 English =로 검색하면 됩니다.

아니면 Englsih =로 검색한 다음 위치를 임시 변수에 놓고 거꾸로 거슬러 올라가서 Name =이 나올 때 까지 검색하고 저장된 위치로 돌아가면 됩니다.

재벌 2세가 재벌이 될 확률과
금메달리스트 2세가 금메달을 딸 확률이 비슷해지도록
자유오픈소스 대안화폐를 씁시다.

아이디의 아이디어 무한도전
http://blog.aaidee.com

귀태닷컴
http://www.gwitae.com

kkb의 이미지

먼저 답변 감사드립니다

Name = 부터 Name = 까지 자르는 방법은 좋은 방법이 아닌 것 같습니다
마지막 학생의 경우에 문제가 생기고 학생들 순서가 반드시 정해져있어야 한다는 조건이 필요하기 때문입니다
English로 검색하는 것은 효율적이지 못합니다

학생들 이름은 항상 유니크합니다
제 생각에도 학생이름을 먼저 찾고 이후에 가장 먼저 나오는 english를 찾아서 수정하면 될 것 같습니다만
그런데 이렇게 어떻게 할 수 있나요?

스크립트로? sed로? C언어 코드로? 무엇을 이용해서 어떻게 하는 것이 좋은가요?

cleansugar의 이미지

그럼 전체 문서를 데이터베이스 등에 CSV 라이브러리를 이용해 전부 복사한 다음 디비 쿼리로 검색하는 건 어떨까요?

마이크로소프트 액세스 등으로도 가능합니다.

아까 말씀드린데로 영어를 먼저 검색하고 역순으로 찾는 게 제일 나을텐데 질문 내용을 더 자세히 알고 싶군요.

이해가 어려우시면 매행 처음에 행번호를 붙였다고 생각하시면 됩니다.

영어가 나오면 하나씩 빼서 Name =이 나올 때가 그 영어점수 주인입니다.

아니면 일단 Name=을 검색해서 현재 포인터가 가리키는 이름을 임시 변수에 저장한 다음

다시 영어가 나오면 임시변수에 저장되어있던 이름이 그 주인이 되는 거죠.

아니면 정규표현식으로 Name = 뒤에 오는 Enlgish =들을 찾아서 배열에 넣어라하면 됩니다.

재벌 2세가 재벌이 될 확률과
금메달리스트 2세가 금메달을 딸 확률이 비슷해지도록
자유오픈소스 대안화폐를 씁시다.

아이디의 아이디어 무한도전
http://blog.aaidee.com

귀태닷컴
http://www.gwitae.com

kkb의 이미지

답변해주셔서 감사드립니다

아... 제가 설명이 부족했던 거 같네요
english로 계속 검색해가면서 학생들의 english 점수를 전부 수정하는 것이 아니고
Lee 이름의 english만 검색해서 점수를 한번 수정하는 것이 한번의 동작의 전부입니다
이 부분 설명이 부족했습니다

작은 임베디드 리눅스 시스템이고요
일단 데이터베이스를 이용할 수도 없지만
파일의 데이터 하나를 수정하는데 데이터베이스 이용하는 것은
호미로 막을 것을 가래로 막는 것이고

제 질문은 위에 댓글에서

학생들 이름은 항상 유니크합니다
제 생각에도 학생이름을 먼저 찾고 이후에 가장 먼저 나오는 english를 찾아서 수정하면 될 것 같습니다만
그런데 이렇게 어떻게 할 수 있나요?

스크립트로? sed로? C언어 코드로? 무엇을 이용해서 어떻게 하는 것이 좋은가요?

익명 사용자의 이미지

infile = File.open "test.txt", "r"
outfile = File.open "out.txt", "w"
name ='Lee'
subject = 'science'
score = 100
 
def find_replace infile, outfile, name, subject, replace
    while(line = infile.readline and !infile.eof?)
        if line.split[2] == name
            outfile.puts line
 
            while(line = infile.readline and !infile.eof?)
                if line.split[0] == subject
                    outfile.puts "#{line.split[0]} #{line.split[1]} #{100}"
                    break
                else
                    outfile.puts line
                end
            end
        else
            outfile.puts line
        end
    end
end
 
find_replace infile, outfile, name, subject, 100
익명 사용자의 이미지

버그가 있어서 조금 수정했습니다.

#!/usr/bin/ruby
 
def find_replace infile, outfile, name, subject, score
    while(line = infile.readline and !infile.eof?)
        if line.split[2] == name
            outfile.puts line
 
            while(line = infile.readline and !infile.eof?)
                if line.split[0] == subject
                    outfile.puts "#{line.split[0]} #{line.split[1]} #{score}"
                    break
                else
                    outfile.puts line
                end
            end
        else
            outfile.puts line
        end
    end
end
 
infile = File.open "test.txt", "r"
outfile = File.open "out.txt", "w"
find_replace infile, outfile, 'Lee', 'science', 100

혹시 버그 있으면 알아서 고쳐서 쓰세요.

kkb의 이미지

답변해주셔서 감사드립니다

근데 이거 언어가 뭔가요? 스크립트 언어인가요?
아니면 수도 코드인가요?

익명 사용자의 이미지

루비 언어에요.
참고로 .txt 파일을 순차 검색하는 것보다... gdbm 같은 파일 DB 로 변환하여 작업하면 더 편하고 빠를지도...

aero의 이미지

$ cat score.txt
Name = Kim
english = 88
science = 90
Name = Lee
math = 92
english = 88
science = 90
Name = Park
math = 92
english = 88
science = 90
korean = 99

$ perl -p0777 -e 'BEGIN{$name="Lee"; $score=11} s/(Name.*?=.*?$name\n.*?english.*?=.*?)\d+(.*?)(Name|$)/\1$score\2\3/s' score.txt
Name = Kim
english = 88
science = 90
Name = Lee
math = 92
english = 11
science = 90
Name = Park
math = 92
english = 88
science = 90
korean = 99
kkb의 이미지

답변주신 분들께 감사드립니다

그런데, 위에서 말씀드렸듯이 작은 임베디드 리눅스 시스템이고
루비나 펄은 설치되어 있지 않습니다
일부러 답변주셨는데 죄송스럽습니다

셸 스크립트나 C언어 코드로는 많이 어려운가요?
파이썬은 설치되어 있는지도 모르겠네요...

익명 사용자의 이미지


C로하면 어렵지 않죠..
입력패턴이 얼마나 정형화되어있느냐에 따라거,
구현이 엄청 간단할 수도 있고 제법 복잡할 수도 있겠습니다.
쉽게 생각하면 trivial한 문제이고,
그렇게 구현하고 나면 이런저런 추가 조건이 나올수 있는 경우이기 때문에,
C코드를 드리기는 어렵겠습니다.

스크립트로 하는 것이 좀 더 직관적이고, 일반적으로 구현할 수 있을것 같은데,
먼저 사용가능한 툴을 정확히! 알려주시는게 좋겠네요..

perl도 안되면 python도 기대하기 어려울것 같고,
shell도 제한적일 것 같고,
sed는 사용가능한가요? 사용가능한 sed 버전도 같이 알려주셔야할듯..

kkb의 이미지

# sed --version
This is not GNU sed version 4.0
BusyBox v1.14.1

python 버전은 2.4.4 입니다

C코드를 알려주시는 것은 저도 무리가 있다고 생각합니다
단지, 파일의 데이터를 읽어서 문자열 변수에 복사해서 어떤 어떤 함수를 이용하고 또 어떤 어떤 함수도 이용하고...
이런 식의 방법 정도만 알려주셔도 제가 짜볼 수 있을 것 같습니다

익명 사용자의 이미지

위에 루비 소스 조금 고쳐서 python 으로 만들면 되겠군요. file io 만 바꿔주면 돌아갈 것 같은데..

익명 사용자의 이미지

알고리즘은 동일하고 file io 뿐만 아니라 여러 부분을 바꿔야 되는군요.
위에 펄 소스의 정규 표현식을 뽑아서 python 으로 돌릴 수도 있습니다.
건투를 빕니다.

kkb의 이미지

일단 다른 분의 답변에서 sed로 해결했습니다

공부도 할겸 python으로도 한번 해보고 싶은 욕심에
위에 올려주신 코드를 python 코드로 조금 바꿔서 실행시켜보고 있습니다
python을 잘 몰라서 아직 잘 안되네요^^;
기본문법을 좀 찾아서 익혀보고 python으로도 한번 해보려고 합니다

도움말씀 주신 답변에 다시 한번 감사드립니다

백수의 이미지

데이터를 먼저 정리해보는게 낫겠네요.
CSV format 을 쓰거나, start/end tag 를 써서 record 를 구별하거나..
아예 xml 을 쓰거나.. 그러면 좀 더 코드를 유연하게 가져갈 수 있습니다.
이런 데이터라면 데이터 검증/예외 처리가 지저분해 질겁니다.

key = val 형식으로 빈칸 한개로 구별되어 있다고 가정하고 대충 짜본겁니다.
이런 humble code 는 익명으로 올려야 제맛.. -0-
다음 레코드를 미리 읽어두는게 나을 것 같긴 한데, 귀찮아서 그냥 파일 포인터 이동시켰습니다.
데이터 파싱하는 부분은 데이터에 따라 strtok 나 strsep 등으로 적절히 바꾸면 될 듯하네요.

#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
 
struct st_record
{
	char name[256];
	int math;
	int eng;
	int sci;
};
 
#define REC_FILE	"infile.txt"
static FILE *fp = NULL;
 
void endrecent(void)
{
	if (fp)
	{
		fclose(fp);
		fp = NULL;
	}
}
 
void setrecent(void)
{
	endrecent();
	fp = fopen(REC_FILE, "r");
}
 
static inline void init_rec(struct st_record *r)
{
	memset(r, 0x00, sizeof(struct st_record));
	r->math = -1;
	r->eng = -1;
	r->sci = -1;
}
 
static inline void set_rec(struct st_record *r, const char *key, const char *val)
{
	assert(key && val);
 
	if (!strcasecmp(key, "Name"))
	{
		strncpy(r->name, val, sizeof(r->name));
		r->name[sizeof(r->name) - 1] = 0x00;
	}
	else if (!strcasecmp(key, "math"))
		r->math = atoi(val);
	else if (!strcasecmp(key, "english"))
		r->eng = atoi(val);
	else if (!strcasecmp(key, "science"))
		r->sci = atoi(val);
}
 
static inline char *split_at(char *p, char delim)
{
	while (*p && *p != delim && *p != '\n')
		++p;
 
	if (*p)
		*p++ = 0x00;
 
	return p;
}
 
static inline void parse_rec(char *buf, char **key, char **val)
{
	char *next, *tok;
 
	*key = *val = NULL;
 
	tok = buf;
	next = split_at(tok, ' ');	/* key */
	*key = tok;
 
	tok = next;
	next = split_at(tok, ' ');	/* = */
 
	tok = next;
	next = split_at(tok, ' ');	/* value */
	*val = tok;
}
 
struct st_record *getrecent(void)
{
	static struct st_record rec;
	char buf[BUFSIZ];
	char *key, *val;
	fpos_t pos;
	bool run;
 
	if (fp == NULL)
		return NULL;
 
	init_rec(&rec);
 
	run = false;
	while (true)
	{
		fgetpos(fp, &pos);	/* save current position */
 
		if (!fgets(buf, sizeof(buf), fp))
			break;
 
		if (run && !strncasecmp(buf, "Name", strlen("Name")))
		{
			fsetpos(fp, &pos);	/* restore saved position for next read */
			break;
		}
 
		split_at(buf, '\n');	/* remove trailing \n */
		parse_rec(buf, &key, &val);
		set_rec(&rec, key, val);
		run = true;
	}
 
	return run?(&rec):NULL;
}
 
void fputrec(FILE *fp, struct st_record *r)
{
	fprintf(fp, "Name = %s\n", r->name);
	fprintf(fp, "math = %d\n", r->math);
	fprintf(fp, "english = %d\n", r->eng);
	fprintf(fp, "science = %d\n", r->sci);
	fflush(fp);
}
 
int main(void)
{
	struct st_record *rec;
	FILE *outfp = stdout;
 
	setrecent();
	while ((rec = getrecent()))
	{
		/* can manipulate record here */
		fputrec(outfp, rec);
	}
	endrecent();
 
	return EXIT_SUCCESS;
}
eseo의 이미지

이렇게 해보면 어떨까요?

name=Lee
subject=english
grade=99
sed -e "/Name = $name/,/$subject = /s/$subject =.\+/$subject = $grade/" $file

---
배려하는 마음을 갖자.

kkb의 이미지

정말 감사드립니다
너무 잘 되네요

공부도할겸 토대로 응용해보려고 합니다
다시 한번 감사드립니다
좋은 하루 되세요

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.