最近幫朋友寫了一個百度競價關鍵詞快速分詞(分組)工具,支持與或邏輯分組,附源碼和工具下載連接

需求很簡單:linux

有一堆關鍵詞(短句),須要給它們分組。分組邏輯很簡單:給出一些歸類詞語,把包含這些歸類詞語的關鍵詞歸到一類。ios

歸類詞語須要支持簡單的與或算術邏輯,例如「日記|博客」,意思就是把包含日記或者博客關鍵詞歸到一類。算法

例如這兩個關鍵詞都符合歸類要求:日記軟件,博客工具shell

又如:「社保&藥店」,意思是把包含社保又包含藥店的關鍵詞歸到一類。ide

例如:北京的社保藥店就符合歸類要求,但若是隻是北京社保局就不符合歸類要求工具

再如:「(日記|博客)&(社保&藥店)」,意思是把即符合「日記|博客」歸類要求,又符合「社保&藥店」歸類要求的關鍵詞歸到一類。測試

 

一個實際例子:編碼

如今有下面的關鍵詞:spa

附近專業保潔公司

北京清潔公司

家政公司

北京好的家政公司

保姆

家教公司

有名的家政

口碑好的保姆


歸類詞語以下:code

(專業|好的|有名)&(清潔|家政)&公司

北京&家政

附近

保姆

家政|清潔

分類結果以下:

 

 這是另外一個案例分詞結果截圖:

 

其實這個需求在linux下直接用grep工具加上簡單的shell仍是很容易作的,但讓我朋友爲了這個從頭學shell和linux不太現實,因此我幫他作了這個工具。若是有人有興趣也能夠去下載:

下載地址:

連接:https://pan.baidu.com/s/1r6YR8qJGOBxvA9GDPsevzw
提取碼:8dmn

===============================================

下面是相關代碼,裏面用到了中序表達式轉成後序表達式計算的技巧

stdafx.h

 1 // stdafx.h : 標準系統包含文件的包含文件,
 2 // 或是常常使用但不常更改的
 3 // 特定於項目的包含文件
 4 //
 5 
 6 #pragma once
 7 
 8 #include "targetver.h"
 9 
10 #include <stdio.h>
11 #include <tchar.h>
12 
13 #define NUMOF(arr) (sizeof(arr)/sizeof(arr[0]))
14 
15 
16 // TODO: 在此處引用程序須要的其餘頭文件
17 #include <string>
18 #include <vector>
19 #include <iostream>
20 #include <stack>
21 using namespace std;

 

GetWord.h

 1 #pragma once
 2 #include "stdafx.h"
 3 
 4 #define TYPE_WORD 0
 5 #define TYPE_AND 1
 6 #define TYPE_OR 2
 7 #define TYPE_BOOL 3
 8 #define TYPE_LEFT 4
 9 #define TYPE_RIGHT 5
10 
11 typedef struct 
12 {
13     int nWordType;
14     string sValue;
15 
16     void output()
17     {
18         switch (nWordType)
19         {
20         case TYPE_WORD:
21             cout << "TYPE_WORD " <<sValue << endl;
22             break;
23         case TYPE_AND:
24             cout << "TYPE_AND" << endl;
25             break;
26         case TYPE_OR:
27             cout << "TYPE_OR" << endl;
28             break;
29         case TYPE_BOOL:
30             cout << "TYPE_BOOL" << endl;
31             break;
32         case TYPE_LEFT:
33             cout << "TYPE_LEFT" << endl;
34             break;
35         case TYPE_RIGHT:
36             cout << "TYPE_RIGHT" << endl;
37             break;
38         default:
39             cout << "unknow" << endl;
40             break;
41         }
42     }
43 }ST_WORD;
44 
45 class CGetWord
46 {
47 public:
48     CGetWord(const char *str);
49     ~CGetWord(void);
50     void rewrind(); //重置到開頭
51     bool getWord(ST_WORD &opr); //讀取一個單詞
52 
53 private:
54     char *m_strInput;
55     int m_nPos;
56 };

PostfixExpressions.h

 1 #pragma once
 2 #include "GetWord.h"
 3 
 4 class CPostfixExpressions
 5 {
 6 public:
 7     CPostfixExpressions(void);
 8     bool parse(const char *strIntermediateOrerExpressions); //輸入中序 轉換成後綴表達式 方便計算
 9     bool grep(const char *str); 
10     ~CPostfixExpressions(void);
11     void showExpr()
12     {
13         cout << "m_expr.size() = " << m_expr.size() << endl;
14         for (size_t i = 0; i < m_expr.size(); ++i)
15         {
16             m_expr[i].output();
17         }
18     }
19 private:
20     vector<ST_WORD> m_expr;
21 };

targetver.h

1 #pragma once
2 
3 // 包括 SDKDDKVer.h 將定義可用的最高版本的 Windows 平臺。
4 
5 // 若是要爲之前的 Windows 平臺生成應用程序,請包括 WinSDKVer.h,並將
6 // WIN32_WINNT 宏設置爲要支持的平臺,而後再包括 SDKDDKVer.h。
7 
8 #include <SDKDDKVer.h>

divide_group.cpp

  1 // divide_group.cpp : 定義控制檯應用程序的入口點。
  2 //
  3 
  4 #include "stdafx.h"
  5 #include "GetWord.h"
  6 #include "PostfixExpressions.h"
  7 
  8 bool checkHaveNotGbk(const char *buf, const size_t nLen)
  9 {
 10     //檢查是否有非GBK字符(不嚴謹)
 11     //碰到非英文字符
 12     bool bHaveNotGbk = false;
 13     for (size_t i = 0; i < nLen; ++i)
 14     {
 15         /*
 16         GBK 亦採用雙字節表示,整體編碼範圍爲 8140-FEFE,首字節在 81-FE 之間,尾字節在 40-FE 之間,剔除 xx7F 一條線。
 17         總計 23940 個碼位,共收入 21886 個漢字和圖形符號,其中漢字(包括部首和構件)21003 個,圖形符號 883 個。
 18         */
 19         unsigned char ch = buf[i];
 20         if ((ch & 0x80) != 0)
 21         {
 22             if (ch >= 0x81 && ch <= 0xfe)
 23             {
 24                 ch = buf[++i];
 25                 if (!(ch >= 0x40 && ch <= 0xFe && ch != 0x7F))
 26                 {
 27                     bHaveNotGbk = true;
 28                     break;
 29                 }
 30             }
 31             else
 32             {
 33                 bHaveNotGbk = true;
 34                 break;
 35             }
 36         }
 37     }
 38 
 39     return bHaveNotGbk;
 40 }
 41 
 42 char *getline(char *buf, size_t nBufSize, FILE *fp)
 43 {
 44     if ( fgets(buf, nBufSize, fp) == NULL)
 45     {
 46         return NULL;
 47     }
 48 
 49     size_t nLen = strlen(buf);
 50     if (nLen > 0 && buf[nLen - 1] == '\n')
 51     {
 52         buf[--nLen] = '\0';
 53     }
 54 
 55     if (checkHaveNotGbk(buf, nLen))
 56     {
 57         cerr << "疑似有非GBK編碼字符[" << buf << "]" << endl;
 58         buf[0] = '\0';
 59     }
 60     return buf;
 61 }
 62 
 63 void outputResult(vector< vector<string> >& vecExprGrepSentence)
 64 {
 65     size_t nMaxJ = 0;
 66 
 67     for (size_t i = 0; i < vecExprGrepSentence.size(); ++i)
 68     {
 69         if (nMaxJ < vecExprGrepSentence[i].size())
 70         {
 71             nMaxJ = vecExprGrepSentence[i].size();
 72         }
 73     }
 74 
 75     for (size_t j = 0; j < nMaxJ; ++j)
 76     {
 77         for (size_t i = 0; i < vecExprGrepSentence.size(); ++i)
 78         {
 79             if (j < vecExprGrepSentence[i].size())
 80             {
 81                 cout << vecExprGrepSentence[i][j] << ",";
 82             }
 83             else
 84             {
 85                 cout << ",";
 86             }
 87         }
 88 
 89         cout << endl;
 90     }
 91 }
 92 
 93 int _tmain(int argc, _TCHAR* argv[])
 94 {
 95     if (argc < 3)
 96     {
 97         printf("usage:divide_group 詞根文件 關鍵詞文件\n");
 98         return 0;
 99     }
100 
101     bool bSplitMoreFlag = false; //標記一個關鍵詞是否能夠被多個詞根匹配
102     if (argc > 3 && argv[3][0] == '1')
103     {
104         bSplitMoreFlag = true;
105     }
106 
107     vector<CPostfixExpressions> vecExprs;
108     vector< vector<string> > vecExprGrepSentence;
109 
110     FILE *fpKey = fopen(argv[1], "r");
111     if (fpKey == NULL)
112     {
113         cout << "詞根文件打不開" << endl;
114         return -1;
115     }
116 
117 
118     FILE *fpSentence = fopen(argv[2], "r");
119     if (fpSentence == NULL)
120     {
121         cout << "關鍵詞文件打不開" << endl;
122         fclose(fpKey);
123         return -10;
124     }
125 
126     CPostfixExpressions expr;
127     vector<string> vecGroup;
128     char buf[1024];
129     vecExprs.reserve(100);
130     vecGroup.resize(1);
131 
132     while (getline(buf, sizeof(buf), fpKey))
133     {
134         if (buf[0] == '\0')
135         {
136             continue;
137         }
138 
139         if (expr.parse(buf))
140         {
141             //暫時不處理
142         }
143         else
144         {
145             cerr << "詞根[" << buf << "]異常 忽略" << endl;
146         }
147 
148         vecExprs.push_back(expr);
149         vecGroup[0] = buf;
150         vecExprGrepSentence.push_back(vecGroup);
151     }
152 
153     if (vecExprs.size() == 0)
154     {
155         cerr << "詞根[" << buf << "]文件異常" << endl;
156         return -20;
157     }
158 
159     size_t nNoGrep = vecExprs.size();
160     vecGroup[0] = "未分組";
161     vecExprGrepSentence.push_back(vecGroup);
162 
163     while (getline(buf, sizeof(buf), fpSentence))
164     {
165         if (buf[0] == '\0')
166         {
167             continue;
168         }
169 
170         bool bGrepFlag = false;
171         for (size_t i = 0; i < vecExprs.size(); ++i)
172         {
173             if (vecExprs[i].grep(buf))
174             {
175                 vecExprGrepSentence[i].push_back(buf);
176                 bGrepFlag = true;
177 
178                 if (!bSplitMoreFlag)
179                 {
180                     //關鍵字匹配到一個詞根後就再也不繼續匹配
181                     break;
182                 }
183             }
184         }
185 
186         if (!bGrepFlag)
187         {
188             vecExprGrepSentence[nNoGrep].push_back(buf);
189         }
190     }
191 
192     outputResult(vecExprGrepSentence);
193     fclose(fpKey);
194     fclose(fpSentence);
195     return 0;
196 }

GetWord.cpp

  1 #include "StdAfx.h"
  2 #include "GetWord.h"
  3 
  4 
  5 CGetWord::CGetWord(const char *str)
  6 {
  7     size_t nLen = strlen(str) + 1;
  8 
  9     m_strInput = new char[nLen];
 10     strcpy(m_strInput, str);
 11     m_nPos = 0;
 12 }
 13 
 14 
 15 CGetWord::~CGetWord(void)
 16 {
 17     delete []m_strInput;
 18     m_strInput = NULL;
 19     m_nPos = 0;
 20 }
 21 
 22 void CGetWord::rewrind()
 23 {
 24     m_nPos = 0;
 25 }
 26 
 27 //獲取一個單詞
 28 bool CGetWord::getWord(ST_WORD &opr)
 29 {
 30     char ch = m_strInput[m_nPos];
 31     if (ch == '\0')
 32     {
 33         return false;
 34     }
 35 
 36     opr.sValue = "";
 37     switch (ch)
 38     {
 39     case '&':
 40         opr.nWordType = TYPE_AND;
 41         ++m_nPos;
 42         break;
 43     case '|':
 44         opr.nWordType = TYPE_OR;
 45         ++m_nPos;
 46         break;
 47     case '(':
 48         opr.nWordType = TYPE_LEFT;
 49         ++m_nPos;
 50         break;
 51     case ')':
 52         opr.nWordType = TYPE_RIGHT;
 53         ++m_nPos;
 54         break;
 55     default:
 56         int i = 0;
 57         opr.nWordType = TYPE_WORD;
 58         for (i = m_nPos; m_strInput[i] != '\0'; ++i)
 59         {
 60             ch = m_strInput[i];
 61 
 62             //碰到操做符,說明關鍵字結束了
 63             if (ch == '&' || ch == '|' || ch == '(' || ch == ')')
 64             {
 65                 break;
 66             }
 67             else
 68             {
 69                 opr.sValue += ch;
 70 
 71                 if (ch & 0x80)
 72                 {
 73                     //中文 兩個字符
 74                     ++i;
 75                     opr.sValue += m_strInput[i];
 76                     continue;
 77                 }
 78             }
 79         }
 80         m_nPos = i;
 81         break;
 82     }
 83 
 84     return true;
 85 }
 86 
 87 
 88 int testCGetWord()
 89 {
 90     char *strExpr[] = {"(計算機&專業)|廣工",
 91         "計算機&廣東",
 92         "計算機|好的|專業"};
 93 
 94     for (int i = 0; i < NUMOF(strExpr); ++i)
 95     {
 96         CGetWord expr(strExpr[i]);
 97         ST_WORD opr;
 98 
 99 
100         cout << strExpr[i] << endl;
101 
102         while (expr.getWord(opr))
103         {
104             opr.output();
105         }
106 
107         cout << "------------" << endl;
108     }
109     return 0;
110 }

PostfixExpressions.cpp

  1 #include "StdAfx.h"
  2 #include "PostfixExpressions.h"
  3 
  4 /*
  5 #define TYPE_WORD 0
  6 #define TYPE_AND 1
  7 #define TYPE_OR 2
  8 #define TYPE_BOOL 3
  9 #define TYPE_LEFT 4
 10 #define TYPE_RIGHT 5
 11 */
 12 
 13 const static int compare[6][6] =
 14 {
 15     0, 0, 0, 0, 0, 0,
 16     0, 1, -1, 0, -1, 0,
 17     0, 1, 1, 0, -1, 0, //TYPE_OR
 18     0, 0, 0, 0, 0, 0,
 19     0, -1, -1, 0, -1, 0, //TYPE_LEFT
 20     0, 1, 1, 0, 0, 0
 21 };
 22 
 23 CPostfixExpressions::CPostfixExpressions(void)
 24 {
 25 }
 26 
 27 
 28 CPostfixExpressions::~CPostfixExpressions(void)
 29 {
 30 }
 31 
 32 
 33 bool CPostfixExpressions::parse(const char *strIntermediateOrerExpressions)
 34 {
 35     /*
 36     InfixExp(中序表達式)轉換PostfixExp(後序表達式)算法:
 37 
 38     1)當輸入的是操做數時候,直接輸出到後序表達式PostfixExp序列中
 39 
 40     2)當輸入開括號時候,把它壓棧
 41 
 42     3)當輸入的是閉括號時候,先判斷棧是否爲空,若爲空,則發生錯誤並進行相關處理。若非空,把棧中元素依次彈出並輸出到Postfix中,知道遇到第一個開括號,若沒有遇到開括號,也發生錯誤,進行相關處理
 43 
 44     4)當輸入是運算符op(+、- 、×、/)時候
 45 
 46     a)循環,當(棧非空and棧頂不是開括號and棧頂運算符的優先級不低於輸入的運算符的優先級)時,反覆操做:將棧頂元素彈出並添加到Postfix中
 47 
 48     b)把輸入的運算符op壓棧
 49 
 50     5)當中序表達式InfixExp的符號序列所有讀入後,若棧內扔有元素,把他們依次彈出並放到後序表達式PostfixExp序列尾部。若彈出的元素遇到空括號,則說明不匹配,發生錯誤,並進行相關處理
 51     */
 52     
 53     m_expr.clear();
 54     m_expr.reserve(100);
 55 
 56     CGetWord expr(strIntermediateOrerExpressions);
 57     ST_WORD opr;
 58     const ST_WORD *pOprTop;
 59 
 60     stack<ST_WORD> stackOperators;
 61     //vector<ST_WORD> vecSymbol;
 62 
 63     bool bExpectWord = true; //第一個元素必須是關鍵字
 64     while (expr.getWord(opr))
 65     {
 66         switch (opr.nWordType)
 67         {
 68         case TYPE_WORD:
 69             if (!bExpectWord)
 70             {
 71                 cerr << "語法錯誤1:不指望的關鍵字" << endl;
 72                 m_expr.clear();
 73                 return false;
 74             }
 75             m_expr.push_back(opr);
 76             bExpectWord = false; //不能出現連續關鍵字
 77             break;
 78         case TYPE_AND:
 79         case TYPE_OR:
 80             if (bExpectWord)
 81             {
 82                 cerr << "語法錯誤2:不指望的操做符" << endl;
 83                 m_expr.clear();
 84                 return false;
 85             }
 86             bExpectWord = true; //不能出現連續操做符
 87         case TYPE_LEFT:
 88             if (stackOperators.size() == 0)
 89             {
 90                 stackOperators.push(opr);
 91             }
 92             else
 93             {
 94                 pOprTop = &stackOperators.top();
 95 
 96                 while (compare[opr.nWordType][pOprTop->nWordType] > 0)
 97                 {
 98                     m_expr.push_back(*pOprTop);
 99                     stackOperators.pop();
100 
101                     if (stackOperators.size() == 0)
102                     {
103                         break;
104                     }
105 
106                     pOprTop = &stackOperators.top();
107                 }
108 
109                 stackOperators.push(opr);
110             }
111             break;
112         case TYPE_RIGHT:
113             if (stackOperators.size() == 0)
114             {
115                 cerr << "語法錯誤3:右括號不匹配左括號1" << endl;
116                 m_expr.clear();
117                 return false;
118             }
119             else
120             {
121                 const ST_WORD *pOprTop = &stackOperators.top();
122 
123                 while (compare[opr.nWordType][pOprTop->nWordType] > 0)
124                 {
125                     m_expr.push_back(*pOprTop);
126                     stackOperators.pop();
127 
128                     if (stackOperators.size() == 0)
129                     {
130                         cerr << "語法錯誤4:右括號不匹配左括號2" << endl;
131                         m_expr.clear();
132                         break;
133                     }
134 
135                     pOprTop = &stackOperators.top();
136                 }
137 
138                 //把左括號出棧
139                 stackOperators.pop();
140             }
141             break;
142         default:
143             cerr << "語法錯誤5:未知類型" << endl;
144             m_expr.clear();
145             return false;
146         }
147     }
148 
149     if (bExpectWord)
150     {
151         cerr << "語法錯誤6:缺乏關鍵字" << endl;
152         m_expr.clear();
153         return false;
154     }
155 
156     size_t nLeft = stackOperators.size();
157 
158     for (size_t i = 0; i < nLeft; ++i)
159     {
160         pOprTop = &stackOperators.top();
161         if (pOprTop->nWordType == TYPE_LEFT)
162         {
163             cerr << "語法錯誤7:右括號不匹配左括號3" << endl;
164             m_expr.clear();
165             return false;
166         }
167         m_expr.push_back(*pOprTop);
168         stackOperators.pop();
169     }
170 
171     return true;
172 }
173 
174 bool CPostfixExpressions::grep(const char *str)
175 {
176     if (m_expr.size() == 0)
177     {
178         cerr << "分組錯誤1,多是表達式有問題" << endl;
179         return false;
180     }
181 
182 
183     vector<ST_WORD> expr = m_expr;
184 
185     //先把關鍵字轉換成布爾值
186     for (size_t i = 0; i < expr.size(); ++i)
187     {
188         if (expr[i].nWordType == TYPE_WORD)
189         {
190             expr[i].nWordType = TYPE_BOOL;
191             if (strstr(str, expr[i].sValue.c_str()) != NULL)
192             {
193                 expr[i].sValue = "1";
194             }
195             else
196             {
197                 expr[i].sValue = "0";
198             }
199         }
200     }
201 
202     if (m_expr.size() == 1)
203     {
204         return expr[0].sValue[0] == '1';
205     }
206 
207     stack<ST_WORD> stackOper;
208     ST_WORD tmpResult;
209     tmpResult.nWordType = TYPE_BOOL;
210     tmpResult.sValue = "1";
211 
212     for (size_t i = 0; i < expr.size(); ++i)
213     {
214         if (expr[i].nWordType == TYPE_BOOL)
215         {
216             stackOper.push(expr[i]);
217         }
218         else
219         {
220             if (stackOper.size() < 2)
221             {
222                 cerr << "分組錯誤2,多是表達式有問題" << endl;
223                 return false;
224             }
225 
226             const ST_WORD right = stackOper.top();
227             stackOper.pop();
228             const ST_WORD left = stackOper.top();
229             stackOper.pop();
230 
231             int nResult;
232 
233             if (expr[i].nWordType == TYPE_AND)
234             {
235                 nResult = (left.sValue[0] - '0') && (right.sValue[0] - '0');
236             }
237             else
238             {
239                 nResult = (left.sValue[0] - '0') || (right.sValue[0] - '0');
240             }
241 
242             tmpResult.sValue[0] = nResult + '0';
243 
244             //計算結果放回操做數堆棧
245             stackOper.push(tmpResult);
246         }
247     }
248 
249     if (tmpResult.sValue[0] == '1')
250     {
251         return true;
252     }
253     else
254     {
255         return false;
256     }
257 }
258 
259 
260 
261 
262 void testParse()
263 {
264     char *strExpr[] = {"單詞",
265         "雙詞&與",
266         "雙詞&或",
267         "三詞&與|或",
268         "三詞|或&與",
269         "三詞&與&與",
270         "三詞|或|或",
271         "(計算機&專業)|廣工",
272         "計算機&廣東",
273         "計算機|好的|專業",
274         "(美麗|專業&低薪)|測試",
275         "(計算機&帥哥)&廣工",
276         "(美麗&賢惠|計算機&專業)|廣工&北大",
277         "(計算機&帥哥)&廣工(美麗&賢惠|計算機&專業)|廣工&北大",
278         "(計算機(帥哥&廣工))",
279         "((帥哥&廣工)計算機)",
280         "計算機(帥哥&廣工))",
281         "(計算機(帥哥&廣工)",
282         "計算機(帥哥&廣工)",
283         "&",
284         "&&",
285         "我&"};
286 
287     for (int i = 0; i < NUMOF(strExpr); ++i)
288     {
289         CPostfixExpressions expr;
290 
291 
292         cerr << strExpr[i] << endl;
293         if (expr.parse(strExpr[i]))
294         {
295             cerr << "語法正確" << endl;
296             expr.showExpr();
297         }
298         else
299         {
300             cerr << "語法錯誤" << endl;
301         }
302         cerr << "------------" << endl;
303     }
304 }
305 
306 
307 void testGrep(int argc, _TCHAR* argv[])
308 {
309     char *strExpr[] = {"(計算機&專業)|廣工",
310         "計算機&廣東",
311         "計算機|好的|專業",
312         "(美麗|專業&低薪)|測試",
313         "(計算機&帥哥)&廣工",
314         "計算機&(帥哥&廣工)",
315         "(美麗&賢惠|計算機&專業)|廣工&北大",
316         "(計算機|(帥哥&廣工))",
317         "廣工",
318         "咱們"};
319 
320     char *strInput[] = {
321         "計算機",
322         "黃詞輝",
323         "廣工",
324         "專業",
325         "黃詞輝 計算機 廣工畢業 帥哥",
326         "美麗 計算機 廣工畢業 賢惠",
327         "專業 計算機 廣工畢業 賢惠",
328         "黃詞輝 計算機 廣工畢業 賢惠",
329         "美麗 計算機 專業 帥哥",
330         "低薪 計算機 專業 帥哥",
331         "黃詞輝 計算機 測試 帥哥",
332         "咱們曾經一塊兒奮鬥 廣工"
333     };
334     //     testParse();
335     //     return true;
336     for (int i = 0; i < NUMOF(strExpr); ++i)
337     {
338         CPostfixExpressions expr;
339 
340 
341         cerr << "詞根:" << strExpr[i] << endl;
342         if (expr.parse(strExpr[i]))
343         {
344             for (int j = 0; j < NUMOF(strInput); ++j)
345             {
346                 cerr << "匹配 " << strInput[j];
347                 if (expr.grep(strInput[j]))
348                 {
349                     cerr << " 成功" << endl;
350                 }
351                 else
352                 {
353                     cerr << " 失敗" << endl;
354                 }
355             }
356         }
357         else
358         {
359             cerr << "語法錯誤" << endl;
360         }
361         cerr << "------------" << endl;
362     }
363 }

stdafx.cpp

1 // stdafx.cpp : 只包括標準包含文件的源文件
2 // divide_group.pch 將做爲預編譯頭
3 // stdafx.obj 將包含預編譯類型信息
4 
5 #include "stdafx.h"
6 
7 // TODO: 在 STDAFX.H 中
8 // 引用任何所需的附加頭文件,而不是在此文件中引用
相關文章
相關標籤/搜索