2121import com .hankcs .hanlp .dictionary .CoreDictionary ;
2222import com .hankcs .hanlp .dictionary .CustomDictionary ;
2323import com .hankcs .hanlp .dictionary .other .CharTable ;
24+ import com .hankcs .hanlp .dictionary .other .CharType ;
2425import com .hankcs .hanlp .model .perceptron .tagset .NERTagSet ;
2526import com .hankcs .hanlp .seg .CharacterBasedSegment ;
27+ import com .hankcs .hanlp .seg .NShort .Path .AtomNode ;
2628import com .hankcs .hanlp .seg .common .Term ;
29+ import com .hankcs .hanlp .utility .Predefine ;
2730
2831import java .util .*;
2932
@@ -37,6 +40,25 @@ public class AbstractLexicalAnalyzer extends CharacterBasedSegment implements Le
3740 protected Segmenter segmenter ;
3841 protected POSTagger posTagger ;
3942 protected NERecognizer neRecognizer ;
43+ /**
44+ * 字符类型表
45+ */
46+ protected static byte [] typeTable ;
47+ /**
48+ * 是否执行规则分词(英文数字标点等的规则预处理)。规则永远是丑陋的,默认关闭。
49+ */
50+ protected boolean enableRuleBasedSegment = false ;
51+
52+ static
53+ {
54+ typeTable = new byte [CharType .type .length ];
55+ System .arraycopy (CharType .type , 0 , typeTable , 0 , typeTable .length );
56+ for (char c : Predefine .CHINESE_NUMBERS .toCharArray ())
57+ {
58+ typeTable [c ] = CharType .CT_CHINESE ;
59+ }
60+ typeTable [CharTable .convert ('·' )] = CharType .CT_CHINESE ;
61+ }
4062
4163 public AbstractLexicalAnalyzer ()
4264 {
@@ -88,7 +110,7 @@ public void hit(int begin, int end, CoreDictionary.Attribute value)
88110 {
89111 if (begin != offset [0 ])
90112 {
91- segmenter . segment (sentence .substring (offset [0 ], begin ), normalized .substring (offset [0 ], begin ), wordList );
113+ segmentAfterRule (sentence .substring (offset [0 ], begin ), normalized .substring (offset [0 ], begin ), wordList );
92114 }
93115 while (attributeList .size () < wordList .size ())
94116 attributeList .add (null );
@@ -100,12 +122,12 @@ public void hit(int begin, int end, CoreDictionary.Attribute value)
100122 });
101123 if (offset [0 ] != sentence .length ())
102124 {
103- segmenter . segment (sentence .substring (offset [0 ]), normalized .substring (offset [0 ]), wordList );
125+ segmentAfterRule (sentence .substring (offset [0 ]), normalized .substring (offset [0 ]), wordList );
104126 }
105127 }
106128 else
107129 {
108- segmenter . segment (sentence , normalized , wordList );
130+ segmentAfterRule (sentence , normalized , wordList );
109131 }
110132 }
111133
@@ -122,20 +144,20 @@ public void hit(int begin, int end, CoreDictionary.Attribute value)
122144 {
123145 if (begin != offset [0 ])
124146 {
125- segmenter . segment (sentence .substring (offset [0 ], begin ), normalized .substring (offset [0 ], begin ), wordList );
147+ segmentAfterRule (sentence .substring (offset [0 ], begin ), normalized .substring (offset [0 ], begin ), wordList );
126148 }
127149 wordList .add (sentence .substring (begin , end ));
128150 offset [0 ] = end ;
129151 }
130152 });
131153 if (offset [0 ] != sentence .length ())
132154 {
133- segmenter . segment (sentence .substring (offset [0 ]), normalized .substring (offset [0 ]), wordList );
155+ segmentAfterRule (sentence .substring (offset [0 ]), normalized .substring (offset [0 ]), wordList );
134156 }
135157 }
136158 else
137159 {
138- segmenter . segment (sentence , normalized , wordList );
160+ segmentAfterRule (sentence , normalized , wordList );
139161 }
140162 }
141163
@@ -454,6 +476,79 @@ protected List<Term> segSentence(char[] sentence)
454476 return termList ;
455477 }
456478
479+ /**
480+ * CT_CHINESE区间交给统计分词,否则视作整个单位
481+ *
482+ * @param sentence
483+ * @param normalized
484+ * @param start
485+ * @param end
486+ * @param preType
487+ * @param wordList
488+ */
489+ private void pushPiece (String sentence , String normalized , int start , int end , byte preType , List <String > wordList )
490+ {
491+ if (preType == CharType .CT_CHINESE )
492+ {
493+ segmenter .segment (sentence .substring (start , end ), normalized .substring (start , end ), wordList );
494+ }
495+ else
496+ {
497+ wordList .add (sentence .substring (start , end ));
498+ }
499+ }
500+
501+ /**
502+ * 丑陋的规则系统
503+ *
504+ * @param sentence
505+ * @param normalized
506+ * @param wordList
507+ */
508+ protected void segmentAfterRule (String sentence , String normalized , List <String > wordList )
509+ {
510+ if (!enableRuleBasedSegment )
511+ {
512+ segmenter .segment (sentence , normalized , wordList );
513+ return ;
514+ }
515+ int start = 0 ;
516+ int end = start ;
517+ byte preType = typeTable [normalized .charAt (end )];
518+ byte curType ;
519+ while (++end < normalized .length ())
520+ {
521+ curType = typeTable [normalized .charAt (end )];
522+ if (curType != preType )
523+ {
524+ if (preType == CharType .CT_NUM )
525+ {
526+ // 浮点数识别
527+ if (",,.." .indexOf (normalized .charAt (end )) != -1 )
528+ {
529+ if (end + 1 < normalized .length ())
530+ {
531+ if (typeTable [normalized .charAt (end + 1 )] == CharType .CT_NUM )
532+ {
533+ continue ;
534+ }
535+ }
536+ }
537+ else if ("年月日时分秒" .indexOf (normalized .charAt (end )) != -1 )
538+ {
539+ preType = curType ; // 交给统计分词
540+ continue ;
541+ }
542+ }
543+ pushPiece (sentence , normalized , start , end , preType , wordList );
544+ start = end ;
545+ }
546+ preType = curType ;
547+ }
548+ if (end == normalized .length ())
549+ pushPiece (sentence , normalized , start , end , preType , wordList );
550+ }
551+
457552 /**
458553 * 返回用户词典中的attribute的分词
459554 *
@@ -474,13 +569,13 @@ private List<CoreDictionary.Attribute> segmentWithAttribute(String original, Str
474569 }
475570 else
476571 {
477- segmenter . segment (original , normalized , wordList );
572+ segmentAfterRule (original , normalized , wordList );
478573 attributeList = combineWithCustomDictionary (wordList );
479574 }
480575 }
481576 else
482577 {
483- segmenter . segment (original , normalized , wordList );
578+ segmentAfterRule (original , normalized , wordList );
484579 attributeList = null ;
485580 }
486581 return attributeList ;
@@ -594,4 +689,16 @@ private static void combineWords(String[] wordNet, int start, int end, CoreDicti
594689 }
595690 attributeArray [start ] = value ;
596691 }
692+
693+ /**
694+ * 是否执行规则分词(英文数字标点等的规则预处理)。规则永远是丑陋的,默认关闭。
695+ *
696+ * @param enableRuleBasedSegment 是否激活
697+ * @return 词法分析器对象
698+ */
699+ public AbstractLexicalAnalyzer enableRuleBasedSegment (boolean enableRuleBasedSegment )
700+ {
701+ this .enableRuleBasedSegment = enableRuleBasedSegment ;
702+ return this ;
703+ }
597704}
0 commit comments