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


需求很簡單:

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

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

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

又如:“社保&葯店”,意思是把包含社保又包含葯店的關鍵詞歸到一類。

例如:北京的社保葯店就符合歸類要求,但如果只是北京社保局就不符合歸類要求

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

 

一個實際例子:

現在有下面的關鍵詞:

附近專業保潔公司

北京清潔公司

家政公司

北京好的家政公司

保姆

家教公司

有名的家政

口碑好的保姆


歸類詞語如下:

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

北京&家政

附近

保姆

家政|清潔

分類結果如下:

 

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

 

其實這個需求在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 // 引用任何所需的附加頭文件,而不是在此文件中引用

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM