2013년 12월 16일 월요일

txt 파일에서 메일 추출


커뮤니티 활동을 하다보니 과제를 물어보시는분이 있더라..

과제내용인 즉...
특정폴더(하위 디렉토리 내의 파일도 검사 해야 함)에 저장되어 있는 텍스트 파일(txt)의 내용을 검사하여 파일 내 저장 되어있는 “이메일주소”를 찾아 내는 프로그램을 만드시오.

C로 짰고 밥먹으면서 짰던거라 조금 코드가 더럽다.

윈도우용 dirent.h를 include해야한다.
http://www.mediafire.com/view/3ufjapid9foqu9q/dirent.h

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#include <stdio.h>
#include <sys/types.h>
#include "MyQueue.h"
#include "dirent.h"
#pragma warning(disable:4996)
myQueue mQueue;
static int
find_directory(
    const char *dirname)
{
    DIR *dir;
    char buffer[PATH_MAX + 2];
    char *p = buffer;
    const char *src;
    char *end = &buffer[PATH_MAX];
    int ok;
    char * extName;
    /* Copy directory name to buffer */
    src = dirname;
    while (p < end  &&  *src != '\0') {
        *p++ = *src++;
    }
    *p = '\0';
    /* Open directory stream */
    dir = opendir (dirname);
    if (dir != NULL) {
        struct dirent *ent;
        /* Print all files and directories within the directory */
        while ((ent = readdir (dir)) != NULL) {
            char *q = p;
            char c;
            /* Get final character of directory name */
            if (buffer < q) {
                c = q[-1];
            } else {
                c = ':';
            }
            /* Append directory separator if not already there */
            if (c != ':'  &&  c != '/'  &&  c != '\\') {
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
                *q++ = '\\';
#else
                *q++ = '/';
#endif
            }
            /* Append file name */
            src = ent->d_name;
            while (q < end  &&  *src != '\0') {
                *q++ = *src++;
            }
            *q = '\0';
            /* Decide what to do with the directory entry */
            switch (ent->d_type) {
            case DT_REG:
                /* Output file name with directory */
                extName = strrchr(ent->d_name, '.');
                if(extName == NULL) break;
                if(strcmp(extName, ".txt") == 0)
                {
                    //printf("fine txt file : %s\n", ent->d_name);
                    //printf ("%s\n", buffer);
                    enqueue(&mQueue, buffer);
                }
                break;
            case DT_DIR:
                /* Scan sub-directory recursively */
                if (strcmp (ent->d_name, ".") != 0  
                        &&  strcmp (ent->d_name, "..") != 0) {
                    find_directory (buffer);
                }
                break;
            default:
                /* Do not device entries */
                /*NOP*/;
            }
        }
        closedir (dir);
        ok = 1;
    } else {
        /* Could not open directory */
        printf ("Cannot open directory %s\n", dirname);
        ok = 0;
    }
    return ok;
}
void myDir(const char * dirPath)
{
    DIR * dp;
    struct dirent * ent;
    char * extName;
    dp = opendir(dirPath);
    if(dp != NULL)
    {
        while(1)
        {
            ent = readdir(dp);
            if(ent == NULL)
                break;
            extName = strrchr(ent->d_name, '.');
            if(strcmp(extName, ".txt") == 0)
                printf("fine txt file : %s\n", ent->d_name);
        }
    } 
}
int IsAvailableEMail(const char * srcMail)
{
    // 찾음 : 1
    // 없음 : 0
    
    int iAtCount = 0;   //@ 위치
    int iDotCount = 0;  // . 위치
    int i;
    char * eMail = (char*)malloc( strlen(srcMail) + 1 );
    strcpy(eMail, srcMail);
    
    if(strcmp(eMail, "") == 0)    return 0;
    
    for(i = 0; i < strlen(eMail); i++)
    {
        if(i > 0 && eMail[i] == '@' ) iAtCount = i+1;    // ①
        if(iAtCount > 0 && i > iAtCount && eMail[i] == '.') iDotCount = i+1;   // ②
    }
    free(eMail);
    if(i > iDotCount && iAtCount > 0 && iDotCount > 0) return 1;     // ③    
    else return 0;
}
int main()
{
    //입력받은 디렉토리에서 확장자가 .txt인 파일을 찾고
    //큐에 넣은 후 이메일 주소를 뽑아내는 구조
    //큐 초기화
    FILE * fp;
    char buf[1024];
    char * path;
    const char * filePath;
    initQueue(&mQueue);
    
    //디렉토리 순회
    find_directory("C:\\Mail");
    ////제대로 나오는지 출력
    //while( !empty(&mQueue) )
    //{
    //    printf("%s\n", frontQueue(&mQueue));
    //    deQueue(&mQueue);
    //}
    //
    
    //찾은 파일을 열어서 이메일 주소를 확인
    while( !empty(&mQueue) )
    {
        path = frontQueue(&mQueue);
        filePath = path;
        fp = fopen(filePath, "r");
        if(fp != NULL)
        {
            int isEmail;
            char * ch;
            int i;
            //while(fgets(buf, 1024, fp))
            while( 0 < fscanf(fp, "%s", buf) )
            {
                //printf("%s", buf);
                isEmail = IsAvailableEMail(buf);
                if(isEmail)
                {
                    ch = strchr(buf, '"');
                    if(ch != NULL)
                        *ch = ' ';
                    ch = strchr(buf, '(');
                    if(ch != NULL)
                        *ch = ' ';
                    ch = strchr(buf, ')');
                    if(ch != NULL)
                        *ch = ' ';
                    printf("%s\n", buf);
                }
            }
            fclose(fp);
            deQueue(&mQueue);
        }
    }
    destroyQueue(&mQueue);
    
    return 0;
}

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#include <stdio.h>
#include <sys/types.h>
#include "MyQueue.h"
#include "dirent.h"
#pragma warning(disable:4996)
myQueue mQueue;
static int
find_directory(
    const char *dirname)
{
    DIR *dir;
    char buffer[PATH_MAX + 2];
    char *p = buffer;
    const char *src;
    char *end = &buffer[PATH_MAX];
    int ok;
    char * extName;
    /* Copy directory name to buffer */
    src = dirname;
    while (p < end  &&  *src != '\0') {
        *p++ = *src++;
    }
    *p = '\0';
    /* Open directory stream */
    dir = opendir (dirname);
    if (dir != NULL) {
        struct dirent *ent;
        /* Print all files and directories within the directory */
        while ((ent = readdir (dir)) != NULL) {
            char *q = p;
            char c;
            /* Get final character of directory name */
            if (buffer < q) {
                c = q[-1];
            } else {
                c = ':';
            }
            /* Append directory separator if not already there */
            if (c != ':'  &&  c != '/'  &&  c != '\\') {
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)
                *q++ = '\\';
#else
                *q++ = '/';
#endif
            }
            /* Append file name */
            src = ent->d_name;
            while (q < end  &&  *src != '\0') {
                *q++ = *src++;
            }
            *q = '\0';
            /* Decide what to do with the directory entry */
            switch (ent->d_type) {
            case DT_REG:
                /* Output file name with directory */
                extName = strrchr(ent->d_name, '.');
                if(extName == NULL) break;
                if(strcmp(extName, ".txt") == 0)
                {
                    //printf("fine txt file : %s\n", ent->d_name);
                    //printf ("%s\n", buffer);
                    enqueue(&mQueue, buffer);
                }
                break;
            case DT_DIR:
                /* Scan sub-directory recursively */
                if (strcmp (ent->d_name, ".") != 0  
                        &&  strcmp (ent->d_name, "..") != 0) {
                    find_directory (buffer);
                }
                break;
            default:
                /* Do not device entries */
                /*NOP*/;
            }
        }
        closedir (dir);
        ok = 1;
    } else {
        /* Could not open directory */
        printf ("Cannot open directory %s\n", dirname);
        ok = 0;
    }
    return ok;
}
void myDir(const char * dirPath)
{
    DIR * dp;
    struct dirent * ent;
    char * extName;
    dp = opendir(dirPath);
    if(dp != NULL)
    {
        while(1)
        {
            ent = readdir(dp);
            if(ent == NULL)
                break;
            extName = strrchr(ent->d_name, '.');
            if(strcmp(extName, ".txt") == 0)
                printf("fine txt file : %s\n", ent->d_name);
        }
    } 
}
int IsAvailableEMail(const char * srcMail)
{
    // 찾음 : 1
    // 없음 : 0
    
    int iAtCount = 0;   //@ 위치
    int iDotCount = 0;  // . 위치
    int i;
    char * eMail = (char*)malloc( strlen(srcMail) + 1 );
    strcpy(eMail, srcMail);
    
    if(strcmp(eMail, "") == 0)    return 0;
    
    for(i = 0; i < strlen(eMail); i++)
    {
        if(i > 0 && eMail[i] == '@' ) iAtCount = i+1;    // ①
        if(iAtCount > 0 && i > iAtCount && eMail[i] == '.') iDotCount = i+1;   // ②
    }
    free(eMail);
    if(i > iDotCount && iAtCount > 0 && iDotCount > 0) return 1;     // ③    
    else return 0;
}
int main()
{
    //입력받은 디렉토리에서 확장자가 .txt인 파일을 찾고
    //큐에 넣은 후 이메일 주소를 뽑아내는 구조
    //큐 초기화
    FILE * fp;
    char buf[1024];
    char * path;
    const char * filePath;
    initQueue(&mQueue);
    
    //디렉토리 순회
    find_directory("C:\\Mail");
    ////제대로 나오는지 출력
    //while( !empty(&mQueue) )
    //{
    //    printf("%s\n", frontQueue(&mQueue));
    //    deQueue(&mQueue);
    //}
    //
    
    //찾은 파일을 열어서 이메일 주소를 확인
    while( !empty(&mQueue) )
    {
        path = frontQueue(&mQueue);
        filePath = path;
        fp = fopen(filePath, "r");
        if(fp != NULL)
        {
            int isEmail;
            char * ch;
            int i;
            //while(fgets(buf, 1024, fp))
            while( 0 < fscanf(fp, "%s", buf) )
            {
                //printf("%s", buf);
                isEmail = IsAvailableEMail(buf);
                if(isEmail)
                {
                    ch = strchr(buf, '"');
                    if(ch != NULL)
                        *ch = ' ';
                    ch = strchr(buf, '(');
                    if(ch != NULL)
                        *ch = ' ';
                    ch = strchr(buf, ')');
                    if(ch != NULL)
                        *ch = ' ';
                    printf("%s\n", buf);
                }
            }
            fclose(fp);
            deQueue(&mQueue);
        }
    }
    destroyQueue(&mQueue);
    
    return 0;
}


실행결과

조금 어설프긴 하지만 돌아가는거에서 만족..!

for 향상문


자바에서는 향상된 for문이라고 하는것 같은데

C++에서는 range base for 라고 한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
int NumberList[] = {1,2,3,4,5};
 
//기존 for문
for(int index=0; i < sizeof(NumberList) / sizeof(NumberList[0]) ; index++)
{
    std::cout << NumberList[index] << std::endl;
}
 
//range base for문
for(auto index : NumberList)
{
    std::cout << index << std::endl;
}
 
기본 for문과 비교했을때 컨테이너를 순회 했을때 더 간단한 구조를 보였다.

하지만 이렇게 되면 값을 수정할 수 없을 것 같은데..?

이런 생각이 들어 찾아봤지만 역시나... 참 바보같은 생각이었다.

1
2
3
4
5
6
7
8
9
 
int NumberList[] = {1,2,3,4,5};
 
//range base for문
for(auto & index : NumberList)
{
    index++;        
}
 


이렇게 하면 그냥 된다 ㅠ


C++에 익숙해지려면 시간이 더 걸릴듯 하다.

임베디드 프로그래밍 C코드 최적화 - 1


임베디드 프로그래밍 C코드 최적화를 읽고 정리...



임베디드 환경은 리소스가 부족하다.

여기서 리소스라 하면 메모리가 될수도 있고, CPU 성능이 될 수도 있고, 디스크의 남은 용량도 될수 있다.(요즘에는 라즈베리파이, 오드로이드 등등 조그만 고성능 보드들이 저가에 나오고 있지만 아직은 바로 바꿀것 같진 않다.)

그래서 메모리가 부족하거나, 디스크(롬)의 남은 용량이 부족하거나 하는 상황에 마주치고는 하는데 이를 위해 최적화가 필요한 것이다. x86이라면 굳이 해주지 않아도 될 정도의 리소스를 가지고 있어 굳이 최적화가 필요없다.


최적화의 방법들

1. 변수를 남발하기보다는 비트연산을 사용하자.
2. 포인터 없이 메모리에 접근할 수 있다.

 1
2
3
4
5
6
7
8
9
10
#define PA  (*(volatile unsigned char *)0x30000000)
int main (void)
{
    PA |= (0x7 << 5);
    return 0;
}

3. 컴파일러를 너무 믿지 말고 volatile 키워드를 쓰자.
    컴파일러가 똑똑하지만 우리는 컴파일러에게 속고 있을 수도 있다.
    volatile의 기능적 의미는 캐시사용안함이다. 보통 프로그램이 실행될 때 속도를 위해 필요한 데이터를 메모리에서 직접 읽어오지 않고 캐시로부터 읽어온다. 하지만, 하드웨어에 의해서 변경되는 값들은 캐시에 즉각적으로 반영되지 않으므로 데이터를 캐시로부터 읽어오지 말고 주 메모리에서 직접 읽어오도록 해야한다. 이러한 특성 때문에 하드웨어가 사용하는 메모리는 volatile로 선언해야 하드웨어에 의해 변경된 값들이 프로그램에 제대로 반영된다. - 

   이 키워드는 멀티코어 프로그래밍에서도 중요하게 사용되니 잊지 말자

4. 개발툴을 잘 이해하라.
   함수 호출 시 인자를 몇 개로 지정하는 것이 효과적인가는 컴파일러마다 다르므로 컴파일러를 잘 이해하는 것이 중요하다.


5. 포인터 체인을 제거하라

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Point
{
    int x,y,z;
};
struct Obj
{
    Point *p1, *d;
};
void draw(struct Obj *a)
{
    a->p1->x = 0;
    a->p1->y = 0;
    a->p1->z = 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct Point
{
    int x,y,z;
  
};
struct Obj
{
    Point *p1, *d;
};
void draw(struct Obj * a)
{
    struct Point *k = a->p1;
    k->x = 0;
    k->y = 0;
    k->z = 0;
}
위쪽의 코드는 a를 접근할 때 매번 a를 다시 읽어오기 때문에 성능의 저하가 일어난다는 것이다.

6. register 변수를 활용해라.

7. 적절한 데이터 타입을 선택해라.
   데이터 버스는 데이터가 이동하는 통로이므로 데이터 버스의 폭은 프로세서에서 데이터를 한 번에 읽어오는 양과 직접적인 관계가 있다. 32비트 프로세서의 경우 데이터 버스의 폭이 4바이트이다. 이 프로세서에서 double형의 데이터를 메모리로부터 읽어오려면, double 데이터 타입의 크기가 8바이트이므로 4바이트의 버스 폭으로 데이터를 가져오려면 두번의 액세스가 필요하다. 그럼, 4바이트보다 작은 데이터 타입을 읽을때도 마찬가지로 효율성이 떨어진다. - 150P


http://kldp.org/node/79109
http://www.joinc.co.kr/modules/moniwiki/wiki.php/Site/C/Documents/COptimization
를 참고하면 더 좋은 이야기를 들을 수 있을 것이다.