小桥流水 | 生活 | 2012 年 04 月 29 日 | 169次阅读
血的教训,献给北漂一族

半个月前,就开始找房子了……找了一个周末,没有找到合适的,主要是中介手中基本都没有房子。第二天在公司的一个qq群里看到一个一个消息,三居3000,觉得真心便宜。是一个同事好心帮邻居转的。应该是他们小区也有一个qq群吧,然后那个同事在他们小区的qq群里看到的吧。

当时,我就加了qq,聊得很好,很快就约好晚上去看房子。晚上,我跟一个同学就去看房子了,觉得房子真心好呀,时间与我的时间也很合适,月底到期,当时就定下来了。房主在看房子的过程,感觉很好说话,各种东西都答应了呀。没冰箱,就答应买个冰箱,没洗衣机就答应给个洗衣机,没空调就答应给装个空调。事后觉得,这种口头答应的事情必须要落实成文字。在后来的交流中,她的口头答应就大打折扣了。

后来,我们就交定金了,她说交个200~500。我那个同学当时觉得交少了不靠谱,就给了300。当时她给我们写个收条,但是没有约定违约责任以及入住时间(时间很重要,最后我在跟她谈赔偿的时候,她就让我等……),这是失误中的失误呀。注意了,交定金的时候,一定要约定违约责任。其实,如果你看到了好房子,最好的办法就是尽快签订合同,合同可以从北京工商局的网站上下载格式合同,一定要把各个细节都落实好。约定违约要赔一个月房租神马的。

今天,到了都快要搬家的日子,她让他现在的房客(不知道真假)给我打电话说他肋骨摔断了,根本就搬不出去,操,说得真鸡巴可怜,你妈,怎么没摔死。总之,最后意思是不租给我们了。后来我跟她聊,她说有两方面原因,一个是现在的房客搬不走,另一个就是租金太便宜。你妈,我觉得这鸡巴就是第二个原因了,都怪自己缺乏社会经验了。后来我给她发短信谈赔偿的问题,让她赔我300,你妈,她鸡巴让我等一个月,有木有……

真心希望她尽快把定金退给我吧,要是不退的话,只能报警或者鸡巴起诉她了。操,把老子惹急了,我也打一回官司……真鸡巴蛋疼。

眼看现在住的房子马上就要到期了,这叫我如何是好……好在经过今天下午的努力,从中介手里找到了一个还算凑合的房子,虽然交了中介费,但别不靠谱了。今天估计是郁闷坏了,我竟然豁出去跟房主砍价,砍了150/月,中介费搞成八五折。

吃亏是福,希望下次能吸取经验,不要再有贪小便宜的心理了吧……

小桥流水 | 技术,生活 | | 64次阅读
[转]搜狗招聘研究员

在一个技术群里看到的,转发出来,感兴趣的可以试试。个人感觉搜狗挺靠谱的,输入法也算是搜狗的核心战略中重要的一步棋,王小川“三支火箭”中的第一支,最终引导搜狗盈利了。

说实话,我在找工作的时候也去搜狗笔试了,但是当时貌似有点得瑟,各种题都做了一遍,可能人觉得我找工作没有目标吧。后来找了个学妹推荐了一下,通知我去面试,但是听说是广告算法,我就没去了,我还是对纯搜索技术比较感兴趣吧。

职位:助理研究员/副研究员/研究员
工作地点:北京
职位要求: 
1. 对自然语言处理/机器学习/数据挖掘相关技术及应用(语言模型/分词/机器翻译/输入法/推荐系统/用户行为挖掘及分析等)技术有相关项目经验 
2. 计算机或相关专业,硕士或以上学历 
3. 较强的c/c++编程背景和算法基础,有perl、shell等脚本处理经验者更佳 
4. 了解linux基本开发环境 
5. 有较强的分析问题和解决问题的能力,工作有激情 
6. 有中文处理项目经验者优先 
 
搜狗输入法开创了互联网输入法的一个新时代,自2006年问世以来,相继推出互联网大词库、智能组词/人名组词、云输入、用户输入纠错等创新功能,极大提升了中国网民的输入体验和输入效率,获得了三亿搜狗输入法用户的广泛好评,在中文输入法市场占有率稳居第一。搜狗输入法研究组作为搜狗输入法开发团队的一支中坚力量,参与搜狗输入法各平台产品的如下功能模块:
1、词库制作和优化;
2、互联网新词发现;
3、语言模型研究和优化;
4、云输入及海量数据处理;
5、用户数据挖掘和个性化研究;

社招应届不限制,有意者请发信至research_ime_job@sogou-inc.com
工作待遇:20w+ && 搜狗公司期权,具体面议
加入搜狗输入法研究团队,与处于上升期的搜狗公司一起分享成功机会!

小桥流水 | 学习,技术,研究 | | 35次阅读
“失控与控制—探索互联网本质”马化腾与凯文凯利尖峰对话

昨天非常有幸去参加了公司的活动“失控与控制—探索互联网本质”,在加入公司不久就见到了pony。在百度实习的时候,见到过robbin。这么说来,互联网三大巨头已经见到了两,什么时候能见到马云呢?

说实话,第一次参加这么高端的活动,第一次用到同声传译(虽然翻译的效果不是很好),当然还有第一次见到pony。

我们一起去的是部门的三个同事,10号线到金台夕照,然后走路去的。到了时候已经很多人了,已经没有员工位了,只能先站着。

IMG_20120423_141011

好在等到开始的时候,跟我一起去的一个同事争取了一下,我也跟着获得了一个空着的媒体位置。看来不管什么事情,都是需要争取的,以后要多向这位同事学习。

不多说了,直接进入主题吧。首先是pony(马化腾)跟KK(凯文凯利)的对话。探讨了个性化与隐私,平台开放,互联网垄断等多方面的问题,个人感觉挺受启发的,也挺长见识的,感觉比参加技术论坛要好很多。“失控与控制”其实是一个哲学问题。pony在谈到这个问题的时候,拿了“微信”作为一个例子。微信其实是一个无线的产品,但是最初的时候没有放到无线的部门来做,而是放到了广研的团队来做,其实就是一种失控,在产品的初期,一定程度的失控,对于一个产品来说是有好处的。所以公司也比较鼓励公司内部的一定程度的竞争。但当微信这个产品成熟了之后,公司就开始拿各种各样的资源来支持微信的发展,让无线部门也参与进来,这其实就是一种控制。

马化腾与凯文·凯利尖峰对话

总的来讲,参加这次的活动,其实是很有收获的,以后如果有机会,还需要多参加。

IMG_20120423_163814

小桥流水 | 技术,研究 | 2012 年 04 月 19 日 | 26次阅读
第一次参加百度技术沙龙

上周六去参加了一次Infoq与百度合办的“百度技术沙龙”。一直都想写点东西,但是最近一直在忙各种各样的事情,所以一直就拖到了现在。

之前在网站上,我看过这个的视频和ppt,感觉挺不错的,正好也跟一个学妹交流了一下,感觉挺有收获的,所以就报名参加了一下这个活动。

总体感觉很好,但是没有我想象的那么好。也许是我的期望过高了吧。首先是一个百度的工程师来讲的。他是一个很会演讲的人,但是他讲得那些东西吧,是百度两年前的技术,现在都不在用了。这样让我觉得,他其实是为了来演讲而演讲的。感觉这个东西,对我的帮助并不是很大。

后来在回去的地铁上跟他在一起,聊了一些非技术的东西,感觉还是很不错的。也许他可以成为我的一个榜样吧,多研究一些技术,在技术上有所建树,学习那些成熟的架构,在工作中去检验。也许在5年之内,我也可像他一样得到一些物质上的回报吧。

第二个演讲者是58同城的架构师,分享很多他在工作中遇到的问题和提出的解决方案。我的绝大多数的收获可能都是来自于他吧。

下面是在手机上记得笔记,用的思维导图的形式:

百度技术沙龙

小桥流水 | 技术 | 2012 年 03 月 30 日 | 102次阅读
Shell将路径绝对化

今天搞个脚本,想将相对路径转成绝对路径,对于绝对路径保持不变,查了查资料,一下代码满足了我的需要:

小桥流水 | 技术 | 2012 年 03 月 28 日 | 85次阅读
Linux忘记密码之后肿么办

最近装了个linux,装完之后发现root有密码,有木有。那怎么办呢?作为一个搞搜索引擎的,那肯定是要用搜索引擎来查了,最好找到一个可行的办法:

  1. 在grub启动界面,随便选择一个,然后按e,编辑第二行,加入 init=/bin/bash,然后按b启动系统,会自动启动系统到没有用户的模式。注意这种方法,grub没有密码,或者你知道grub的密码,否则就不行了。
  2. 进到shell后,运行mount -n / -o remount,rw,将根分区弄成可读写的。
  3. 运行passwd修改root的密码。如果出现找不到文件/dev/urandom,那就拷贝一个非空文件过去就行了(注意touch一个空文件是不行的)。
  4. 运行mount -n / -o remount,ro,将根分区弄回只读状态。
  5. 到此,root密码已经重置了,重启系统,用刚设置的密码进入系统就可以了。

小桥流水 | 技术 | 2012 年 03 月 27 日 | 65次阅读
解决linux下可以ping通ip,nslookup解析域名正常的问题

在虚拟机里面装了linux,好不容易配置网关之后可以ping通网络了,但发现ping域名时找不到host的情况。试了试nslookup可以正常解析域名。

网上找了一圈发现,要修改配置文件/etc/nsswitch.conf,将

hosts: files

改为,

hosts: files dns

然后就搞定。。。

小桥流水 | 技术,研究 | 2012 年 03 月 25 日 | 127次阅读
多模式匹配

最近工作上要用到多模式匹配的算法,所以就搜索一些资料,写篇博客分享一下。今天开始用word来写博客了,也试试效果。

之前在百度实习的时候,也用到过多模式匹配,但是别的部门提供的一个公共库dictmatch。我搜了看到百度互联网技术官方博客上面还有几篇介绍dictmatch的几篇博客,链接如下:

但是这个对于我来说,略显有点复杂了,我也不想去搞一个这么大的工程。我找了一圈,我们的公共库里面也没有提供这样的算法。另外,我依稀记得这个东西因为是用树的结构来存的,还是比较费内存的。我记得,我当时将这个东西改成hash_map这样的东东来实现的,而且效率也完全可以达到要求的。

记得当时是把模式串(要查找的串)放到hashmap中,然后把被查询串切词,切完词后进行相邻组合然后到hash_map中查询是否存在,对于比较短的被查询串来说这个方法还是比较快的,但是对于长的查询串来说可能就不行了,复杂度是O(n^2),其中n为被查询串切词后的长度。

目前我的做法是对于任意一个模式串,用字符串查找算法来判定是否包含该模式串,复杂度为O(m+n)*k(m表示模式串的长度,n为查询串的长度,k为模式串的数量),这种复杂度已经不能满足我的需求了。

我去网上找了找,多模式匹配算法大概有以下几种:

clip_image002

当然最近几年也会有一些改进的算法。网上找了以下最好一种算法的源码,感觉挺复杂的,要学习这个方法也很费劲。找到了一个比较好的实现,代码如下:

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
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
/***************************************************
*	Original Filename: 		wm.h
*	Created/Modified: 		Andy_guo								
*	Date:					2009/11/22			
*	Main Purpose:			WM算法
*	Comments:	
****************************************************/
#pragma once
 
//哈希表大小
#define HASHTABLESIZE (256*256)
//哈希表类型
#define HASH_TYPE short
//移动表大小
#define SHIFTTABLESIZE (256*256)
//模式串的最大长度MAXN - 1
#define MAXPATTERN 10001	
//单词最大长度为MAXM - 1
#define WORDMAX 51	
 
#include "winsock2.h"
#include "atlstr.h"
 
//=================================//
//模式结构体
//=================================//
typedef struct WMPATTERNSTRUCT
{
	char*				psPat;	//模式内容
	unsigned			psLen;	//模式的长度
	WMPATTERNSTRUCT*	next;	//下一个模式指针
}WMPATTERNSTRUCT;
 
//=================================//
//已经匹配模式结构体
//=================================//
typedef struct matchedPattern
{
	char	matchedPtn[20];	//模式内容
	int		matchedSum;		//模式的长度
 
}MATCHEDPATTERN;
 
//=================================//
//wm综合结构体
//=================================//
typedef struct WMSTRUCT
{
	WMPATTERNSTRUCT*	plist;				//模式指针链表
	WMPATTERNSTRUCT*	msPatArray;			//模式数组,用来存放模式内容
	unsigned short*		msNumArray;			//模式数组中有相同哈希值的个数
	int					msNumPatterns;		//模式数量
	unsigned			msNumHashEntries;	//哈希表条目的数量
	HASH_TYPE*			msHash;				//last 2 characters pattern hash table
	unsigned char*		msShift;			//bad word shift table
	HASH_TYPE*			msPrefix;			//first 2 characters prefix table
	int					msSmallest;			//模式的最小长度
}WMSTRUCT;
 
/****************************************************/
class CWM
{
public:
	CWM(void);
 
	~CWM(void);
 
	//WM综合结构体
	WMSTRUCT* m_pWmStruct;
 
	//已经匹配模式结构体
	MATCHEDPATTERN* m_pMatchedPtn;
 
	//获取指定文件名路径
	/*void GetFilePath(const char* strFileName, char* strFilePath);*/
 
	/**	
	*	建立shift移动表
	*	@pWmStruct		WM结构体指针
	*	@return void
	**/
	void CreateShiftTable(WMSTRUCT* pWmStruct);
 
	/**	
	*	建立prefix前缀表
	*	@pWmStruct		WM结构体指针
	*	@return void
	**/
	void CreatePrefixTable(WMSTRUCT* pWmStruct);
 
	/**	
	*	Hash哈希表的建立
	*	@pWmStruct		WM结构体指针
	*	@return int
	**/
	int CreateHashTable(WMSTRUCT* pWmStruct);
 
	/**	
	*	从配置文件中加载关键词
	*	@pWmStruct		WM结构体指针
	*	@return int
	**/
	int LoadPatternToArray(WMSTRUCT* pWmStruct);
 
	/**	
	*	字符串哈希值从小到大排列
	*	@pWmStruct		WM结构体指针
	*	@return void
	**/
	void Sort(WMSTRUCT* pWmStruct);
 
	/**
	*	WM算法模式匹配
	*	@pchSrcText		要过滤的文本内容
	*	@nTextLen		原文本内容长度
	*	@pList			返回匹配的链表指针
	*	@return	int
	**/
	int WMPatternMatch(unsigned char* pchSrcText, int nTextLen, WMPATTERNSTRUCT** pList);
 
	/**
	*	后缀哈希值相同,比较前缀以及整个字符匹配
	*	@nIndex			散列值
	*	@pchDestText	文本内容
	*	@windowBgn	    匹配模式窗口头
	*	@return	int
	**/
	int WMPrefixMatch(int nIndex, unsigned char* pchDestText, unsigned char* T,WMPATTERNSTRUCT**);
 
	/**
	*	用指定的字符串替换文本中出现的要替换的字符串
	*	@pchInput	 	含特殊字符的字符串
	*	@pchOutput		转换后的字符串
	*	@pSrc			要转换的特殊字符	
	*	@pDst			要转换的目的字符
	*	@return	char*	转换后的字符串指针
	**/
	char* Substitute(char* pInput, char* pOutput, char* pSrc, char* pDst);
 
	/*************************内联、静态函数***************************/
 
	/**
	*	哈希映射函数
	*	@T			哈希函数键值
	*	@return		unsigned short
	**/
	static unsigned short HASH16(unsigned char* T)
	{
		//每个字节放一位字符,前一个字符左移8位与后面的字符
		return (unsigned short) ((*T) << 4 | *(T + 2));
	}
 
	/**
	*	判断是否是单字符
	*	@chChar
	*	@return	bool
	**/
	inline bool IsSingleChar(char chChar)
	{
		return chChar > 0;
	}
 
	/**
	*	判断是否是有效的单字符
	*	@chChar
	*	@return	bool
	**/
	inline bool IsValidSingleChar(char chChar)
	{
		return (chChar >= '0' && chChar <= '9')
			|| (chChar >= 'A' && chChar <= 'Z')
			|| (chChar >= 'a' && chChar <= 'z')
			|| (chChar == ' ');
	}
 
	/**	
	*	判断是否是有效的双字符(中文)
	*	0xA3B0-0xA3B9,全角数字
	*	0xA3C1-0xA3DA,全角大写字母
	*	0xA3E1-0xA3FA,全角小写字母
	*	GBK/2:OxBOA1-F7FE, 收录 GB2312 汉字 6763 个,按原序排列
	*	GBK/3:Ox8140-AOFE,收录 CJK 汉字 6080 个
	*	GBK/4:OxAA40-FEAO,收录 CJK 汉字和增补的汉字 8160 个
	*	@ushChar
	*	@return bool
	**/
	inline bool IsValidDoubleChar(unsigned short ushChar)
	{
		return (ushChar >= 0xA3B0 && ushChar <= 0xA3B9)
			|| (ushChar >= 0xA3C1 && ushChar <= 0xA3DA)
			|| (ushChar >= 0xA3E1 && ushChar <= 0xA3FA)
			|| (ushChar >= 0xB0A0 && ushChar <= 0xF7FF)
			|| (ushChar >= 0x8140 && ushChar <= 0xA0FF)
			|| (ushChar >= 0xAA40 && ushChar <= 0xFEAF);
	}
 
	/**	
	*	半角字符转换成全角字符
	*	@chChar
	*	@return unsigned short
	**/
	inline unsigned short ToDoubleChar(char chChar)
	{
		//全角字符 - 半角字符 = 0xA380 
		return 0xA380 + chChar;
	}
 
	/**	
	*	全角字符转换成半角字符
	*	@ushChar
	*	@return char
	**/
	inline char ToSingleChar(unsigned short ushChar)
	{
		//全角字符 - 半角字符 = 0xA380 
		return ushChar - 0xA380;
	}
 
	/**	
	*	全角字符从小写字母转换成大写字母:两者差0x0020(32)
	*	@ushChar
	*	@return unsigned short
	**/
	inline unsigned short ToUpperChar(unsigned short ushChar)
	{
		if (ushChar >= 0xA3E1 && ushChar <= 0xA3FA)
			return ushChar - 0x0020;
 
		return ushChar;
	}
 
	/**	
	*	全角字符从大写字母转换成小写字母,两者差0x0020(32)
	*	@ushChar
	*	@return unsigned short
	**/
	inline unsigned short ToSmallChar(unsigned short ushChar)
	{
		if (ushChar >= 0xA3C1 && ushChar <= 0xA3DA)
			return ushChar + 0x0020;
 
		return ushChar;
	}
 
	/**
	*	把文本字符串转换成全角字符中的预处理
	*	@pchSrc			原文本字符串
	*	@pchDest		目的字符串
	*	@szLength		原文本字符串长度
	*	@return	size_t
	**/
	inline size_t PreProcess(const char* pchSrc, char* pchDest, size_t szLength)
	{
		const char* pchSrcPos = pchSrc;
		char* pchDestPos = pchDest;
 
		//判断字符串是否越界
		while(pchSrcPos < pchSrc + szLength)
		{
			//判断是单字符
			if (IsSingleChar(*pchSrcPos))
			{
				//判断是否是字母与数字
				if (IsValidSingleChar(*pchSrcPos))
				{
					unsigned short ushChar = ToDoubleChar(*pchSrcPos);
					ushChar = ntohs(ToUpperChar(ushChar));
					memcpy(pchDestPos, &ushChar, 2);
					pchDestPos += 2;
				}
 
				pchSrcPos++;
			}
			//判断是双字符
			else
			{
				//只有一个单字符(最后-最前)
				if (pchSrc + szLength - pchSrcPos < 2)
					break;
 
				//用无符号的短整型存储一个中文字符或宽字符
				unsigned short ushChar;
				memcpy(&ushChar, pchSrcPos, 2);
 
				//将一个无符号短整型数从主机字节顺序转换为网络字节顺序
				ushChar = htons(ToUpperChar(ushChar));
 
				if (IsValidDoubleChar(ushChar))
				{
					//将一个无符号短整型数从网络字节顺序转换为主机字节顺序
					ushChar = ntohs(ToUpperChar(ushChar));
					memcpy(pchDestPos, &ushChar, 2);
					pchDestPos += 2;
				}
 
				pchSrcPos += 2;
			}
		}
 
		return pchDestPos - pchDest;
	}
 
	/**
	*	把全角字符串转换成半角字符串的预处理
	*	@pchSrc			原文本字符串
	*	@pchDest		目的字符串
	*	@szLength		原文本字符串长度
	*	@return	size_t
	**/
	inline size_t ToHalfPreProcess(const char* pchSrc, char* pchDest, size_t szLength)
	{
		const char* pchSrcPos = pchSrc;
		char* pchDestPos = pchDest;
 
		//判断字符串是否越界
		while(pchSrcPos < pchSrc + szLength)
		{
			//用无符号的短整型存储一个中文字符或宽字符
			unsigned short ushChar = 0;
			//中文转换成无符号的短整型的好方法
			memcpy(&ushChar, pchSrcPos, 2);
			ushChar = htons(ushChar);
 
			//判断是否是大写的英文和数字
			if ((ushChar >= 0xA3C1 && ushChar <= 0xA3DA) || 
				(ushChar >= 0xA3B0 && ushChar <= 0xA3B9) ||
				(ushChar == 0xA3A0))
			{
				ushChar = ToSmallChar(ushChar);
				char chChar = ToSingleChar(ushChar);
				memcpy(pchDestPos, &chChar, 1);
				pchDestPos += 1;
			} 
			else
			{
				//只有一个单字符(最后-最前)
				if (pchSrc + szLength - pchSrcPos < 2)
					break;
 
				//用无符号的短整型存储一个中文字符
				ushChar = ntohs(ushChar);
				memcpy(pchDestPos, &ushChar, 2);
				pchDestPos += 2;
			}
 
			pchSrcPos += 2;
		}
 
		return pchDestPos - pchDest;
	}
 
};
 
 
/***************************************************
*	Original Filename: 		wm.cpp
*	Created/Modified: 		Andy_guo
*	Date:					2009/11/22	
*	Main Purpose:			WM算法
*	Comments:	
****************************************************/
#include "WM.h"
 
/****************************************************/
CWM::CWM(void)
{
	//从配置文件中加载关键词
	m_pWmStruct = new WMSTRUCT;
	memset(m_pWmStruct, 0, sizeof(WMSTRUCT));
 
	m_pWmStruct->plist = NULL;
	m_pWmStruct->msPatArray = NULL;
	m_pWmStruct->msNumArray = NULL;
	m_pWmStruct->msHash = NULL;
	m_pWmStruct->msShift = NULL;
	m_pWmStruct->msPrefix = NULL;
	m_pWmStruct->msSmallest = MAXPATTERN - 1;
 
	//加载模式
	LoadPatternToArray(m_pWmStruct);
 
	//字符串哈希值从小到大排列
	Sort(m_pWmStruct);
 
	//建立shift移动表
	CreateShiftTable(m_pWmStruct);
 
	//Hash哈希表的建立
	CreateHashTable(m_pWmStruct);
 
	//建立prefix前缀表
	CreatePrefixTable(m_pWmStruct);
}
 
CWM::~CWM(void)
{
	//释放WM综合结构体
	delete m_pWmStruct;
	m_pWmStruct = NULL;
}
 
/**********************************************
*功  能: 获取指定文件名路径
*参  数: const char*	strFileName		文件名
*	     char*			strFilePath		文件名路径
*返回值:								空
***********************************************/
#if 0
void CWM::GetFilePath(const char* strFileName, char* strFilePath)
{
	//文件路径
	CString pathFile;
 
	//取当前运行模块全路径
	GetModuleFileName(NULL, pathFile.GetBuffer(MAX_PATH), MAX_PATH);
	pathFile.ReleaseBuffer(MAX_PATH);
 
	//返回最后匹配字符序号
	int nIndex = pathFile.ReverseFind('\\');
 
	//取部分路径
	pathFile = pathFile.Left(nIndex);
 
	//取目的文件路径
	pathFile = pathFile + _T("\\") + _T(strFileName);
 
	//拷贝目的文件路径
	memcpy(strFilePath, pathFile.GetBuffer(pathFile.GetLength()), pathFile.GetLength());
	pathFile.ReleaseBuffer();
 
	return;
}
#endif
 
/****************************************************/
//从配置文件中加载关键词
int CWM::LoadPatternToArray(WMSTRUCT* pWmStruct)
{
	//分配WM内存空间
	if (pWmStruct == NULL)
	{
		pWmStruct = new WMSTRUCT;
		memset(pWmStruct, 0, sizeof(WMSTRUCT));
	}
 
#if 1
	int ch = 0; 
	char pchDest[64] = {0};
	//打开文件<关键词.txt>
	FILE* pFile = fopen(".\\关键词.txt","r");
 
	int i = 0;
	//读取文件
	while(!feof(pFile))
	{
		//读入一个数据
		ch = fgetc(pFile);
		if(ch != '\n')
		{
			pchDest[i++] = (char)ch; 
			continue;
		}
		else
			i = 0;
 
		//对关键词预处理
		char pchTemp[64] = {0};
		int size = CWM::PreProcess(pchDest, pchTemp, strlen(pchDest) + 1);
		strcpy_s(pchDest, pchTemp);
 
		//分配模式内存空间
		WMPATTERNSTRUCT* pPatternStruct = new WMPATTERNSTRUCT;
		if (!pPatternStruct) return -1;
		memset(pPatternStruct, 0, sizeof(WMPATTERNSTRUCT));
 
		//给节点赋值
		pPatternStruct->psPat = new char[strlen(pchDest) + 1];
		memset(pPatternStruct->psPat, 0, strlen(pchDest) + 1);
		strcpy_s(pPatternStruct->psPat, strlen(pchDest) + 1, pchDest);
		pPatternStruct->psLen = strlen(pchDest);
 
		//并把此模式加入链表
		pPatternStruct->next = pWmStruct->plist;
		pWmStruct->plist = pPatternStruct;
 
		//更新WM结构体值
		pWmStruct->msNumPatterns++;
		if (pPatternStruct->psLen < (unsigned)pWmStruct->msSmallest)
		{
			pWmStruct->msSmallest = pPatternStruct->psLen;
		}
 
		//清空数组
		memset(pchDest, 0, 64);
	} 
#else
	int ch = 0; 
	char pchDest[32] = {0};
	//打开文件<关键词.txt>
	FILE* pFile = fopen(".\\关键词.txt","r");
 
	//读取文件
	while(fgets(pchDest, 32, pFile) != NULL)
	{
		//分配模式内存空间
		WMPATTERNSTRUCT* pPatternStruct = new WMPATTERNSTRUCT;
		if (!pPatternStruct) return -1;
		memset(pPatternStruct, 0, sizeof(WMPATTERNSTRUCT));
 
		//给节点赋值
		pPatternStruct->psPat = new char[strlen(pchDest) + 1];
		memset(pPatternStruct->psPat, 0, strlen(pchDest) + 1);
		strcpy_s(pPatternStruct->psPat, strlen(pchDest) + 1, pchDest);
		pPatternStruct->psLen = strlen(pchDest);
		printf("%s\n", pPatternStruct->psPat);
		printf("%d\n", pPatternStruct->psLen);
 
		//并把此模式加入链表
		pPatternStruct->next = pWmStruct->plist;
		pWmStruct->plist = pPatternStruct;
 
		//更新WM结构体值
		pWmStruct->msNumPatterns++;
		if (pPatternStruct->psLen < (unsigned)pWmStruct->msSmallest)
		{
			pWmStruct->msSmallest = pPatternStruct->psLen;
		}
 
		//清空数组
		memset(pchDest, 0, 32);
	} 
#endif
 
	//分配模式数组内存空间
	pWmStruct->msPatArray = new WMPATTERNSTRUCT[sizeof(WMPATTERNSTRUCT) * pWmStruct->msNumPatterns];
	if (!pWmStruct->msPatArray)
	{
		printf("ERROR:分配内存空间失败!\n");
		return -1;
	}
 
	//有相同哈希散列值数组空间
	pWmStruct->msNumArray = new unsigned short[sizeof(short) * pWmStruct->msNumPatterns];
	if(!pWmStruct->msNumArray)
	{
		printf("ERROR:分配内存空间失败!\n");
		return -1;
	}
 
	//遍历模式链表,并拷贝到模式数组
	WMPATTERNSTRUCT* pList = NULL;
	int kk;
	for(kk = 0, pList = pWmStruct->plist; 
		pList != NULL && kk < pWmStruct->msNumPatterns; 
		pList = pList->next)
	{
		memcpy(&pWmStruct->msPatArray[kk++], pList, sizeof(WMPATTERNSTRUCT));
	}
 
	return 0;
}
 
/****************************************************/
//字符串哈希值从小到大排列
void CWM::Sort(WMSTRUCT* pWmStruct)
{
	//取所有模式的最小值
	int m = pWmStruct->msSmallest, B = 4;
	unsigned char* temp;
 
	for(int i = pWmStruct->msNumPatterns - 1, flag = 1; i > 0 && flag; i--)
	{
		flag = 0;
		for(int j = 0; j < i; j++)
		{
			//后面的比前面还要小,则交换两者
			if(CWM::HASH16((unsigned char*)&pWmStruct->msPatArray[j + 1].psPat[m - B]) 
				< CWM::HASH16((unsigned char*)&pWmStruct->msPatArray[j].psPat[m - B]))
			{
				flag = 1;
				temp = (unsigned char*)pWmStruct->msPatArray[j + 1].psPat;
				pWmStruct->msPatArray[j + 1].psPat = pWmStruct->msPatArray[j].psPat;
				pWmStruct->msPatArray[j].psPat = (char*)temp;
			}
		}
	}
}
 
/****************************************************/
//建立shift移动表
void CWM::CreateShiftTable(WMSTRUCT* pWmStruct)
{
	//要考虑的一块字符串的大小
	int B = 4;
	//所有模式的最小长度
	int m = pWmStruct->msSmallest;
 
	//建立移动表空间
	pWmStruct->msShift = new unsigned char[SHIFTTABLESIZE * sizeof(char)];
	if(!pWmStruct->msShift) return;
	memset(pWmStruct->msShift, 0, SHIFTTABLESIZE * sizeof(char));
 
	//当模式数量少时,取(B = 2),移动表所有初始值为(m - B + 1)
	//显然,与任何模式都不匹配时值为(m - B + 2)
	for(int i = 0; i < SHIFTTABLESIZE; i++)
		pWmStruct->msShift[i] = (unsigned)(m - B + 2);
 
	//为每个大小为B的字符串映射一个入口
	for(int i = 0; i < pWmStruct->msNumPatterns; i++)
	{
		for(int k = 0; k < m - 2; k++)
		{
			//大小为B的字符串与模式相比,要移动的位数
			//如:(中国)与(中国人)相比,移动2位;(国人)与(中国人)相比,移动0位
			unsigned short nShift = (unsigned short)(m - B - k);
 
#if 1
			//为每个大小为B的字符串匹配一个整数作为移动表的索引
			//匹配时,移动表索引值与哈希表的索引值相同
			unsigned short nIndex = CWM::HASH16((unsigned char*)&pWmStruct->msPatArray[i].psPat[k]);
#else
			//为每个大小为B的字符串匹配一个整数作为移动表的索引
			//匹配时,移动表索引值与哈希表的索引值相同
			unsigned short nIndex = pWmStruct->msPatArray[i].psPat[k] << 4
				| pWmStruct->msPatArray[i].psPat[k + 2];
#endif
 
			//与模式匹配时值shift[i]为(m - q),即到q时要移动的距离
			//如:文本ca与模式cat匹配时,要移动1个距离;at与模式cat匹配时,要移动0个距离
			if(nShift < pWmStruct->msShift[nIndex])
				pWmStruct->msShift[nIndex] = nShift;
 
			k++;
		}
	}
 
	return;
}
 
/****************************************************/
//建立prefix前缀表
void CWM::CreatePrefixTable(WMSTRUCT* pWmStruct)
{
	//建立前缀表空间
	pWmStruct->msPrefix = new HASH_TYPE[sizeof(HASH_TYPE) * (pWmStruct->msNumPatterns)];
	if(!pWmStruct->msPrefix) return;
 
	for(int i = 0; i < pWmStruct->msNumPatterns; i++)
	{
		pWmStruct->msPrefix[i] = CWM::HASH16((unsigned char*)pWmStruct->msPatArray[i].psPat);
	}
 
	return;
}
 
/****************************************************/
//哈希表的建立,计算有多少个不同哈希值,且从小到大
int CWM::CreateHashTable(WMSTRUCT* pWmStruct)
{
	unsigned sindex, hindex, nInGroup;
	int m = pWmStruct->msSmallest;
	int B = 4;
 
	//分配内存空间
	pWmStruct->msNumHashEntries = HASHTABLESIZE;
	pWmStruct->msHash = new HASH_TYPE[sizeof(HASH_TYPE) * pWmStruct->msNumHashEntries];
	if(!pWmStruct->msHash)
	{
		printf("ERROR:分配内存空间出错!\n");
		return -1;
	}
 
	//给哈希表的条目初始化为-1
	for(int i = 0; i < (int)pWmStruct->msNumHashEntries; i++)
	{
		pWmStruct->msHash[i] = (HASH_TYPE) - 1;
	}
 
	//遍历模式列表
	for(int i = 0; i < pWmStruct->msNumPatterns; i++)
	{
		//计算最后B(在这B=4)个字符的哈希值为i
		hindex = CWM::HASH16((unsigned char*)&pWmStruct->msPatArray[i].psPat[m - B]);
		sindex = pWmStruct->msHash[hindex] = i;
 
		//计算最后B个字符的哈希值相等的个数
		nInGroup = 1;
		while(++i < pWmStruct->msNumPatterns && 
			hindex == CWM::HASH16((unsigned char*)&pWmStruct->msPatArray[i].psPat[m - B]))
			nInGroup++;
 
		//把有相同哈希值的个数放入模式数组中
		pWmStruct->msNumArray[sindex] = nInGroup;
		i--;
	}
 
	return 0;
}
 
/********************************************************
* 功 能: WM算法模式匹配
* 参 数: unsigned char*		pchSrcText		要过滤的文本内容
*		 int				nTextLen		原文本内容长度
*		 WMPATTERNSTRUCT*	pList			返回匹配的字符
*返回值:									无
*********************************************************/
int CWM::WMPatternMatch(unsigned char* pchSrcText, int nTextLen, WMPATTERNSTRUCT** pList)
{
	//预处理后的文本缓存
	char pchDestText[1024] = {0};
	memset(pchDestText, 0, 1024);
	nTextLen = strlen((char*)pchSrcText) + 2;
 
	//预处理文本,减少循环次数
	int nDestTextLen = PreProcess((char*)pchSrcText, pchDestText, nTextLen);
 
	//取WM综合结构体
	WMSTRUCT* pWmStruct = m_pWmStruct;
 
	//文本的右边界(尾)
	unsigned char* TextEnd = (unsigned char*)(pchDestText + nDestTextLen);
 
	//若文本比最小的模式的长度还小,退出
	if(nDestTextLen < pWmStruct->msSmallest)
		return -1;
 
	//模式块窗口尾
	unsigned char* windowEnd = (unsigned char*)(pchDestText + pWmStruct->msSmallest);
 
	//1.计算文本当前被扫描的B个字符的哈希值h(从t[m-B+1]...t[m])
	for(unsigned char* windowBgn = (unsigned char*)pchDestText; windowEnd <= TextEnd; windowBgn++, windowEnd++)
	{
		//取移动表shift[i]的值(nShift),若为0,则有匹配
		int nShift = pWmStruct->msShift[*windowBgn << 4 | *(windowEnd - 2)];
 
		//2.检查shift[i]的值nShift,不为0,没有匹配
		while(nShift)
		{
			windowBgn += nShift;
			windowEnd += nShift;
 
			//窗口的边界超出文本尾
			if(windowEnd > TextEnd)
				return -1;
 
			//寻找下一个匹配
			nShift = pWmStruct->msShift[*windowBgn << 4 | *(windowEnd - 2)];
		} 
 
		//移动值为0,找到匹配,取对应的散列值(nIndex)
		int nIndex = pWmStruct->msHash[*windowBgn << 4 | *(windowEnd - 2)];
		if(nIndex  == (HASH_TYPE) - 1) 
			continue;
 
		WMPrefixMatch(nIndex, (unsigned char*)pchDestText, windowBgn, pList);
 
		windowBgn++;
		windowEnd++;
	}
 
	return 0;
}
 
/**********************************************
*功  能: 后缀哈希值相同,比较前缀以及整个字符匹配
*参  数: int			nIndex		散列值
*	     unsigned char* pchDestText	文本初始内容
*	     unsigned char* windowBgn	有匹配的文本头
*返回值:							无
***********************************************/
int CWM::WMPrefixMatch(int nIndex, unsigned char* pchDestText, unsigned char* windowBgn,WMPATTERNSTRUCT** pList)
{
	//取WM综合结构体
	WMSTRUCT* pWmStruct = m_pWmStruct;
 
	//取有相同哈希值头与尾
	WMPATTERNSTRUCT* pPatternBegin = &pWmStruct->msPatArray[nIndex];
	WMPATTERNSTRUCT* pPatternEnd = pPatternBegin + pWmStruct->msNumArray[nIndex];
 
	//3.计算文本前缀哈希值
	int text_prefix = CWM::HASH16(windowBgn);
 
	//4.检查每个满足(HASH[h] <= P < HASH[h+1])的模式P
	for( ; pPatternBegin < pPatternEnd; pPatternBegin++)
	{
		if(pWmStruct->msPrefix[nIndex++] != text_prefix)
			continue;
		else
			//5.当PREFIX[P]=text_prefix,与原文本比较
		{
			unsigned char* pPatternTxt = (unsigned char*)pPatternBegin->psPat;
			unsigned char* pTxt = windowBgn;
 
			//对文本和模式进行直接检查
			while(*(pPatternTxt++) == *(pTxt++) && *(pTxt - 1) != '\0');
 
			//取到匹配的模式
			if(*(pPatternTxt - 1) == '\0')
			{
				printf("Matched pattern is:%s\n", pPatternBegin->psPat);
				//保存已经匹配的模式内容
				WMPATTERNSTRUCT* pMatchedPtn = new WMPATTERNSTRUCT;
				memset(pMatchedPtn, 0, sizeof(WMPATTERNSTRUCT));
 
				pMatchedPtn->psPat = new char[strlen(pPatternBegin->psPat) + 1];
				memset(pMatchedPtn->psPat, 0, strlen(pPatternBegin->psPat) + 1);
				strcpy_s(pMatchedPtn->psPat, strlen(pPatternBegin->psPat) + 1, pPatternBegin->psPat);
				pMatchedPtn->next = *pList;
				*pList = pMatchedPtn;
			}
 
		}
 
	}
 
	return 0;
}
 
/***************************************************
*功  能: 用指定的字符串替换文本中出现的要替换的字符串
*参  数: char* pchInput	 	含特殊字符的字符串
*		 char* pchOutput	转换后的字符串
*		 char* pSrc			要转换的特殊字符	
*		 char* pDst			要转换的目的字符
*返回值:					转换后的字符串
****************************************************/
char* CWM::Substitute(char* pchInput, char* pchOutput, char* pSrc, char* pDst)
{
	char *pchSrc, *pchDst, *pCursor;
	int nSrcLen, nDstLen, nLen;
 
	// 指向输入字符串的游动指针.
	pchSrc = pchInput;
	// 指向输出字符串的游动指针.
	pchDst = pchOutput;
	// 计算被替换串和替换串的长度.
	nSrcLen = strlen(pSrc);
	nDstLen = strlen(pDst);
 
	//查找pchSrc,返回指向字符串中第一次出现替换串的位置指针(找不到则返回null).
	pCursor = strstr(pchSrc, pSrc);
	if(pCursor)
	{
		// 找到
		while(pCursor) 
		{
			// 计算被替换串前边字符串的长度.
			nLen = (int)(pCursor - pchSrc);
			// 复制游标指针前的字符串
			memcpy(pchDst, pchSrc, nLen);
			// 复制替换字符
			memcpy(pchDst + nLen, pDst, nSrcLen/2 + nSrcLen%2);
			// 指针跳过被替换串
			pchSrc = pCursor + nSrcLen;
			// 调整指向输出串的指针位置
			pchDst = pchDst + nLen + nSrcLen/2 + nSrcLen%2;
			// 继续查找
			pCursor = strstr(pchSrc, pSrc);
		}
		// 复制剩余字符串.
		strcpy(pchDst, pchSrc);
	}
	else
	{
		// 没有找到则原样复制.
		strcpy(pchDst, pchSrc);
	}
 
	return pchDst;
}

越看这个代码越觉得复杂。这说明直接上来就代码还是比较困难的,应该先了解清楚了算法,然后才能去看代码或者说是自己来实现代码。

后来我就觉得这样来搞不是很靠谱,自己写一个这样的算法还是比较困难的,所以就想在网络上找个更好的代码,先凑合着用。

网上翻了几个帖子之后,我发现其实我可以用正则表达式来实现我的这个功能,正则表达式中的|(或)直接就可以满足我的需求。就是将所有的模式串或起来,然后搞成一个正则表达式,然后直接用这个正则表达式进行搜索就Ok了,正好能满足我的需求,明天去公司了就准备这么干了。

小桥流水 | 学习,生活 | 2012 年 03 月 21 日 | 75次阅读
封闭培训

很长一段时间没有发博客了,因为这段时间一直的封闭培训。今天上午回到公司,同事们说我胖了。也许真的是胖了吧。培训的时候,每天的伙食其实不差,每天听听课的,仿佛穿越了……回到了大学时代。

回到了公司,就开始干活,一切又回到了去培训之前的样子……说忙不忙,说闲也不闲。不知怎的,有一种莫名的失落感。下班,走在地铁上,把我拉回了这个残酷的现实世界,一下子觉得很孤独,失落。

在知春路地铁站挤十三号线的时候,上车的一瞬间,不知道怎的被人从后边踢了一脚,还是用什么打了一下,还没等我看到是谁干的时候,车门就关了,顿时非常地郁闷,为什么这个世界上有这样的人?也许是别人挤到他下车了吧,为了发泄就来踹我吧。

虽然我一直试图让自己变成一个开朗的人,但我也不得不承认,目前我还是偏内向一些。我内心渴望与人交流,渴望表达自己内心的想法。但真正遇到陌生人的时候,由于内心的恐惧,又表达不出来什么。相比过去,也许现在的我,要好很多了,但这远远不够。

也许还需要时间,今天比昨天更好,明天比今天更好。

小桥流水 | 学习,技术,生活,研究 | 2012 年 03 月 06 日 | 372次阅读
腾讯2012实习生招聘内推启动啦~~~

亲爱的同学们,“腾飞梦想,引领未来”—腾讯2012春季实习生招聘经启动,为了能够使更多优秀的同学脱颖而出,腾讯将实行顶尖技术学生内推计划。

此次内推主要针对2013年毕业的应届毕业生,内推岗位主要面向技术类、产品类。欢迎大家踊跃报名~~
通过内推你可以:
1、提前获取与高层技术官面谈的机会,
2、获得校招项目组的重点关注和帮助
3、了解更加真实的腾讯

4、提前加入腾讯实习
内推资格:
职位大类:

技术类(软件开发、安全技术、技术研究)、产品类(产品策划、运营)


兴趣方向包括
移动互联网、云平台、游戏开发、网络媒体、网络与桌面安全、数据及网络平台、技术研究、即时通讯、搜索开发(内推信息表内有各方向的介绍)

 

如果你满足以下特征之一:
1、突出的专业成绩和技术能力
2、很强的研究成果、论文、专利或参与学术会议
3、是有分量的专业竞赛中(如ACM)成绩突出的获奖者
4、具备知名互联网相关企业的实习经验
5、知名企业俱乐部核心技术成员,具备良好的社会实践经历

那么,联系我们:
简历内推投递格式:个人详细简历+内推信息表(见附件)
简历请以“学校+姓名+兴趣方向”的方式来命名,如大连理工大学+王五+搜索开发
内推简历投递邮箱: dlutwy@qq.com 或 youwang@tencent.com(最好是前者,后者我不知道能不能收到)
内推简历投递截止时间为:2012年3月20日

被推荐人注意:请务必于3月12日以后在join.qq.com注册并在线提交简历

附件:2012腾讯实习生招聘内部推荐模板