浏览代码

语料库词典根据搜索关键字 生成汉字 播放笔顺 生成拼音,每一笔生成汉字,部分简繁切换,展开收起,

qinpeng 2 年之前
父节点
当前提交
b169d4d056

二进制
src/assets/teacherdev/down.png


二进制
src/assets/teacherdev/speaker-one.png


二进制
src/assets/teacherdev/up.png


+ 9 - 1
src/components/corpus/Strockplayredline.vue

@@ -1,6 +1,8 @@
 <!--  -->
 <template>
-  <div class="strockplayRedInner">
+  <div
+    :class="[isHighlight ? 'strockplayRedInner_xiao' : 'strockplayRedInner']"
+  >
     <!-- <div
       @click="playHanzi"
       :class="[
@@ -23,6 +25,7 @@
         @click="playHanzi"
       /> -->
       <img
+        v-if="playStorkes"
         class="strock-play-red"
         src="../../assets/teacherdev/strock-play-red-click-big.png"
         alt=""
@@ -156,6 +159,11 @@ export default {
   width: 128px; //444px
   height: 128px; //480px
 }
+.strockplayRedInner_xiao {
+  position: relative;
+  width: 64px; //444px
+  height: 64px; //480px
+}
 
 .character-target-div {
   width: 100%;

+ 2 - 2
src/components/teacher-dev/TeachingTool.vue

@@ -20,7 +20,7 @@
         </div>
         <p>文本分析</p>
       </div>
-      <!-- <div>
+      <div>
         <div
           style="background: #d86046"
           @click="
@@ -32,7 +32,7 @@
           <img src="../../assets/teacherdev/jygj-2.png" alt="" />
         </div>
         <p>语料库词典</p>
-      </div> -->
+      </div>
     </div>
   </div>
 </template>

+ 4 - 0
src/main.js

@@ -15,6 +15,10 @@ import "@/common/font/font.css"
 import "@/permission"
 import i18n from "@/utils/i18n"
 
+
+import zh_tran from "@/utils/lang.js"
+Vue.prototype.$zh_tran = zh_tran
+
 // element 下拉框下拉加载
 Vue.directive('loadmore', {
     bind(el, binding) {

文件差异内容过多而无法显示
+ 6 - 0
src/utils/lang.js


+ 325 - 0
src/utils/pinyinUtil.js

@@ -0,0 +1,325 @@
+/**
+ * 汉字与拼音互转工具,根据导入的字典文件的不同支持不同
+ * 对于多音字目前只是将所有可能的组合输出,准确识别多音字需要完善的词库,而词库文件往往比字库还要大,所以不太适合web环境。
+ * @start 2016-09-26
+ * @last 2016-09-29
+ */
+;
+(function(global, factory) {
+    if (typeof module === "object" && typeof module.exports === "object") {
+        module.exports = factory(global);
+    } else {
+        factory(global);
+    }
+})(typeof window !== "undefined" ? window : this, function(window) {
+
+    var toneMap = {
+        "ā": "a1",
+        "á": "a2",
+        "ǎ": "a3",
+        "à": "a4",
+        "ō": "o1",
+        "ó": "o2",
+        "ǒ": "o3",
+        "ò": "o4",
+        "ē": "e1",
+        "é": "e2",
+        "ě": "e3",
+        "è": "e4",
+        "ī": "i1",
+        "í": "i2",
+        "ǐ": "i3",
+        "ì": "i4",
+        "ū": "u1",
+        "ú": "u2",
+        "ǔ": "u3",
+        "ù": "u4",
+        "ü": "v0",
+        "ǖ": "v1",
+        "ǘ": "v2",
+        "ǚ": "v3",
+        "ǜ": "v4",
+        "ń": "n2",
+        "ň": "n3",
+        "": "m2"
+    };
+
+    var dict = {}; // 存储所有字典数据
+    var pinyinUtil = {
+        /**
+         * 解析各种字典文件,所需的字典文件必须在本JS之前导入
+         */
+        parseDict: function() {
+            // 如果导入了 pinyin_dict_firstletter.js
+            if (window.pinyin_dict_firstletter) {
+                dict.firstletter = pinyin_dict_firstletter;
+            }
+            // 如果导入了 pinyin_dict_notone.js
+            if (window.pinyin_dict_notone) {
+                dict.notone = {};
+                dict.py2hz = pinyin_dict_notone; // 拼音转汉字
+                for (var i in pinyin_dict_notone) {
+                    let temp = pinyin_dict_notone[i];
+                    for (let j = 0, len = temp.length; j < len; j++) {
+                        if (!dict.notone[temp[j]]) dict.notone[temp[j]] = i; // 不考虑多音字
+                    }
+                }
+            }
+            // 如果导入了 pinyin_dict_withtone.js
+            if (window.pinyin_dict_withtone) {
+                dict.withtone = {}; // 汉字与拼音映射,多音字用空格分开,类似这种结构:{'大': 'da tai'}
+                let temp = pinyin_dict_withtone.split(',');
+                for (let i = 0, len = temp.length; i < len; i++) {
+                    // 这段代码耗时28毫秒左右,对性能影响不大,所以一次性处理完毕
+                    dict.withtone[String.fromCharCode(i + 19968)] = temp[i]; // 这里先不进行split(' '),因为一次性循环2万次split比较消耗性能
+                }
+
+                // 拼音 -> 汉字
+                if (window.pinyin_dict_notone) {
+                    // 对于拼音转汉字,我们优先使用pinyin_dict_notone字典文件
+                    // 因为这个字典文件不包含生僻字,且已按照汉字使用频率排序
+                    dict.py2hz = pinyin_dict_notone; // 拼音转汉字
+                } else {
+                    // 将字典文件解析成拼音->汉字的结构
+                    // 与先分割后逐个去掉声调相比,先一次性全部去掉声调然后再分割速度至少快了3倍,前者大约需要120毫秒,后者大约只需要30毫秒(Chrome下)
+                    var notone = pinyinUtil.removeTone(pinyin_dict_withtone).split(',');
+                    var py2hz = {},
+                        py, hz;
+                    for (let i = 0, len = notone.length; i < len; i++) {
+                        hz = String.fromCharCode(i + 19968); // 汉字
+                        py = notone[i].split(' '); // 去掉了声调的拼音数组
+                        for (let j = 0; j < py.length; j++) {
+                            py2hz[py[j]] = (py2hz[py[j]] || '') + hz;
+                        }
+                    }
+                    dict.py2hz = py2hz;
+                }
+            }
+        },
+        /**
+         * 根据汉字获取拼音,如果不是汉字直接返回原字符
+         * @param chinese 要转换的汉字
+         * @param splitter 分隔字符,默认用空格分隔
+         * @param withtone 返回结果是否包含声调,默认是
+         * @param polyphone 是否支持多音字,默认否
+         */
+        getPinyin: function(chinese, splitter, withtone, polyphone) {
+            if (!chinese || /^ +$/g.test(chinese)) return '';
+            splitter = splitter == undefined ? ' ' : splitter;
+            withtone = withtone == undefined ? true : withtone;
+            polyphone = polyphone == undefined ? false : polyphone;
+            var result = [];
+            if (dict.withtone) // 优先使用带声调的字典文件
+            {
+                var noChinese = '';
+                for (var i = 0, len = chinese.length; i < len; i++) {
+                    var pinyin = dict.withtone[chinese[i]];
+                    if (pinyin) {
+                        // 如果不需要多音字,默认返回第一个拼音,后面的直接忽略
+                        // 所以这对数据字典有一定要求,常见字的拼音必须放在最前面
+                        if (!polyphone) pinyin = pinyin.replace(/ .*$/g, '');
+                        if (!withtone) pinyin = this.removeTone(pinyin); // 如果不需要声调
+                        //空格,把noChinese作为一个词插入
+                        noChinese && (result.push(noChinese), noChinese = '');
+                        result.push(pinyin);
+                    } else if (!chinese[i] || /^ +$/g.test(chinese[i])) {
+                        //空格,把noChinese作为一个词插入
+                        noChinese && (result.push(noChinese), noChinese = '');
+                    } else {
+                        noChinese += chinese[i];
+                    }
+                }
+                if (noChinese) {
+                    result.push(noChinese);
+                    noChinese = '';
+                }
+            } else if (dict.notone) // 使用没有声调的字典文件
+            {
+                if (withtone) console.warn('pinyin_dict_notone 字典文件不支持声调!');
+                if (polyphone) console.warn('pinyin_dict_notone 字典文件不支持多音字!');
+                let noChinese = '';
+                for (let i = 0, len = chinese.length; i < len; i++) {
+                    let temp = chinese.charAt(i),
+                        pinyin = dict.notone[temp];
+                    if (pinyin) { //插入拼音
+                        //空格,把noChinese作为一个词插入
+                        noChinese && (result.push(noChinese), noChinese = '');
+                        result.push(pinyin);
+                    } else if (!temp || /^ +$/g.test(temp)) {
+                        //空格,插入之前的非中文字符
+                        noChinese && (result.push(noChinese), noChinese = '');
+                    } else {
+                        //非空格,关联到noChinese中
+                        noChinese += temp;
+                    }
+                }
+
+                if (noChinese) {
+                    result.push(noChinese);
+                    noChinese = '';
+                }
+            } else {
+                throw '抱歉,未找到合适的拼音字典文件!';
+            }
+            if (!polyphone) return result.join(splitter);
+            else {
+                if (window.pinyin_dict_polyphone) return parsePolyphone(chinese, result, splitter, withtone);
+                else return handlePolyphone(result, ' ', splitter);
+            }
+        },
+        /**
+         * 获取汉字的拼音首字母
+         * @param str 汉字字符串,如果遇到非汉字则原样返回
+         * @param polyphone 是否支持多音字,默认false,如果为true,会返回所有可能的组合数组
+         */
+        getFirstLetter: function(str, polyphone) {
+            polyphone = polyphone == undefined ? false : polyphone;
+            if (!str || /^ +$/g.test(str)) return '';
+            if (dict.firstletter) // 使用首字母字典文件
+            {
+                var result = [];
+                for (var i = 0; i < str.length; i++) {
+                    var unicode = str.charCodeAt(i);
+                    var ch = str.charAt(i);
+                    if (unicode >= 19968 && unicode <= 40869) {
+                        ch = dict.firstletter.all.charAt(unicode - 19968);
+                        if (polyphone) ch = dict.firstletter.polyphone[unicode] || ch;
+                    }
+                    result.push(ch);
+                }
+                if (!polyphone) return result.join(''); // 如果不用管多音字,直接将数组拼接成字符串
+                else return handlePolyphone(result, '', ''); // 处理多音字,此时的result类似于:['D', 'ZC', 'F']
+            } else {
+                var py = this.getPinyin(str, ' ', false, polyphone);
+                py = py instanceof Array ? py : [py];
+                let result = [];
+                for (let i = 0; i < py.length; i++) {
+                    result.push(py[i].replace(/(^| )(\w)\w*/g, function(m, $1, $2) { return $2.toUpperCase(); }));
+                }
+                if (!polyphone) return result[0];
+                else return simpleUnique(result);
+            }
+        },
+        /**
+         * 拼音转汉字,只支持单个汉字,返回所有匹配的汉字组合
+         * @param pinyin 单个汉字的拼音,可以包含声调
+         */
+        getHanzi: function(pinyin) {
+            if (!dict.py2hz) {
+                throw '抱歉,未找到合适的拼音字典文件!';
+            }
+            return dict.py2hz[this.removeTone(pinyin)] || '';
+        },
+        /**
+         * 获取某个汉字的同音字,本方法暂时有问题,待完善
+         * @param hz 单个汉字
+         * @param sameTone 是否获取同音同声调的汉字,必须传进来的拼音带声调才支持,默认false
+         */
+        getSameVoiceWord: function(hz, sameTone) {
+            sameTone = sameTone || false
+            return this.getHanzi(this.getPinyin(hz, ' ', false))
+        },
+        /**
+         * 去除拼音中的声调,比如将 xiǎo míng tóng xué 转换成 xiao ming tong xue
+         * @param pinyin 需要转换的拼音
+         */
+        removeTone: function(pinyin) {
+            return pinyin.replace(/[āáǎàōóǒòēéěèīíǐìūúǔùüǖǘǚǜńň]/g, function(m) { return toneMap[m][0]; });
+        },
+        /**
+         * 将数组拼音转换成真正的带标点的拼音
+         * @param pinyinWithoutTone 类似 xu2e这样的带数字的拼音
+         */
+        getTone: function(pinyinWithoutTone) {
+            var newToneMap = {};
+            for (var i in toneMap) newToneMap[toneMap[i]] = i;
+            return (pinyinWithoutTone || '').replace(/[a-z]\d/g, function(m) {
+                return newToneMap[m] || m;
+            });
+        }
+    };
+
+
+    /**
+     * 处理多音字,将类似['D', 'ZC', 'F']转换成['DZF', 'DCF']
+     * 或者将 ['chang zhang', 'cheng'] 转换成 ['chang cheng', 'zhang cheng']
+     */
+    function handlePolyphone(array, splitter, joinChar) {
+        splitter = splitter || '';
+        var result = [''],
+            temp = [];
+        for (var i = 0; i < array.length; i++) {
+            temp = [];
+            var t = array[i].split(splitter);
+            for (var j = 0; j < t.length; j++) {
+                for (var k = 0; k < result.length; k++)
+                    temp.push(result[k] + (result[k] ? joinChar : '') + t[j]);
+            }
+            result = temp;
+        }
+        return simpleUnique(result);
+    }
+
+    /**
+     * 根据词库找出多音字正确的读音
+     * 这里只是非常简单的实现,效率和效果都有一些问题
+     * 推荐使用第三方分词工具先对句子进行分词,然后再匹配多音字
+     * @param chinese 需要转换的汉字
+     * @param result 初步匹配出来的包含多个发音的拼音结果
+     * @param splitter 返回结果拼接字符
+     */
+    function parsePolyphone(chinese, result, splitter, withtone) {
+        var poly = window.pinyin_dict_polyphone;
+        var max = 7; // 最多只考虑7个汉字的多音字词,虽然词库里面有10个字的,但是数量非常少,为了整体效率暂时忽略之
+        var temp = poly[chinese];
+        if (temp) // 如果直接找到了结果
+        {
+            temp = temp.split(' ');
+            for (var i = 0; i < temp.length; i++) {
+                result[i] = temp[i] || result[i];
+                if (!withtone) result[i] = pinyinUtil.removeTone(result[i]);
+            }
+            return result.join(splitter);
+        }
+        for (let i = 0; i < chinese.length; i++) {
+            temp = '';
+            for (var j = 0; j < max && (i + j) < chinese.length; j++) {
+                if (!/^[\u2E80-\u9FFF]+$/.test(chinese[i + j])) break; // 如果碰到非汉字直接停止本次查找
+                temp += chinese[i + j];
+                var res = poly[temp];
+                if (res) // 如果找到了多音字词语
+                {
+                    res = res.split(' ');
+                    for (var k = 0; k <= j; k++) {
+                        if (res[k]) result[i + k] = withtone ? res[k] : pinyinUtil.removeTone(res[k]);
+                    }
+                    break;
+                }
+            }
+        }
+        // 最后这一步是为了防止出现词库里面也没有包含的多音字词语
+        for (let i = 0; i < result.length; i++) {
+            result[i] = result[i].replace(/ .*$/g, '');
+        }
+        return result.join(splitter);
+    }
+
+    // 简单数组去重
+    function simpleUnique(array) {
+        var result = [];
+        var hash = {};
+        for (var i = 0; i < array.length; i++) {
+            var key = (typeof array[i]) + array[i];
+            if (!hash[key]) {
+                result.push(array[i]);
+                hash[key] = true;
+            }
+        }
+        return result;
+    }
+
+    pinyinUtil.parseDict();
+    pinyinUtil.dict = dict;
+    window.pinyinUtil = pinyinUtil;
+
+});

文件差异内容过多而无法显示
+ 0 - 0
src/utils/pinyin_dict_withtone.js


+ 179 - 19
src/views/corpus/Result.vue

@@ -2,36 +2,67 @@
   <div class="result" v-loading="loading">
     <Header :projectShow="true" />
     <div class="main">
-      <div class="hanzi_list" v-if="">
+      <div class="hanzi_list">
+        <div class="top_jf">
+          <div class="j_f">
+            <div :class="[JFIndex == 0 ? 'sele' : '']" @click="jfEvent(0)">
+              简
+            </div>
+            <div :class="[JFIndex == 1 ? 'sele' : '']" @click="jfEvent(1)">
+              繁
+            </div>
+          </div>
+        </div>
         <div
           class="list_one"
-          v-for="(item, index) in hzData"
+          v-for="(item, index) in ShowHzData"
           :key="'index' + index"
         >
           <Strockplayredline
             v-if="item.hzDetail.hz_json"
-            :Book_text="item.con"
-            :playStorkes="false"
+            :Book_text="JFIndex == 0 ? item.con : item.fanti"
+            :playStorkes="true"
             :curItem="item.hzDetail"
             :targetDiv="'bwcHanziIntp' + index + item.con"
             :isHighlight="false"
             :judgeAnswer="2"
           />
-          <div
-            v-for="(items, indexs) in item.hzDetail.hz_json.medians.length"
-            :key="'row' + indexs"
-          >
-            <Strockplayredline
-              v-if="item.hzDetail.hz_json"
-              :Book_text="item.con"
-              :playStorkes="false"
-              :curItem="item.hzDetail"
-              :targetDiv="'bwcHanziIntp_height' + index + item.con + indexs"
-              :isHighlight="true"
-              :judgeAnswer="indexs + 1"
-            />
+          <div class="Highlight" v-if="item.hzDetail.hz_json">
+            <div class="play_audio">
+              <img src="../../assets/teacherdev/speaker-one.png" alt="" />
+              <span>{{ item.pinyin }}</span>
+            </div>
+            <div
+              v-for="(items, indexs) in item.hzDetail.hz_json.medians.length"
+              :key="'row' + indexs"
+              class="row"
+            >
+              <Strockplayredline
+                v-if="item.hzDetail.hz_json"
+                :Book_text="JFIndex == 0 ? item.con : item.fanti"
+                :playStorkes="false"
+                :curItem="item.hzDetail"
+                :targetDiv="'bwcHanziIntp_height' + index + item.con + indexs"
+                :isHighlight="true"
+                :judgeAnswer="indexs + 1"
+              />
+              <div class="number">{{ indexs + 1 }}</div>
+            </div>
           </div>
         </div>
+
+        <div class="shouqi">
+          <span @click="updownHz">
+            <template v-if="unfold">
+              <img src="../../assets/teacherdev/up.png" alt="" />
+              收起
+            </template>
+            <template v-else>
+              <img src="../../assets/teacherdev/down.png" alt="" />
+              展开
+            </template>
+          </span>
+        </div>
       </div>
     </div>
   </div>
@@ -43,6 +74,10 @@
 import Header from "@/components/Header";
 import { getLogin } from "@/api/api";
 import Strockplayredline from "@/components/corpus/Strockplayredline";
+import "@/utils/pinyin_dict_withtone";
+import "@/utils/pinyinUtil";
+import seekWord from "@/utils/lang.js";
+
 export default {
   //import引入的组件需要注入到对象中才能使用
   components: {
@@ -53,8 +88,12 @@ export default {
   data() {
     //这里存放数据
     return {
+      JFIndex: 0,
       hzData: [],
+      ShowHzData: [],
       loading: true,
+      lang: null,
+      unfold: true,
     };
   },
   //计算属性 类似于data概念
@@ -63,17 +102,42 @@ export default {
   watch: {},
   //方法集合
   methods: {
+    updownHz() {
+      this.unfold = !this.unfold;
+      if (this.unfold) {
+        this.ShowHzData = JSON.parse(JSON.stringify(this.hzData));
+      } else {
+        this.ShowHzData.splice(2);
+      }
+    },
+    jfEvent(index) {
+      this.JFIndex = index;
+      if (index == 0) {
+        //简体
+      } else {
+        //繁体
+        this.hzData.forEach((item) => {
+          let a = seekWord(item.con);
+          item.fanti = a;
+        });
+        this.gethzJSON();
+      }
+    },
     // 获取汉字josn
     gethzJSON() {
       this.loading = true;
       let MethodName = "hz_resource_manager-GetHZStrokesContent";
       this.hzData.forEach((item) => {
         let data = {
-          hz: item.con,
+          hz: this.JFIndex == 0 ? item.con : item.fanti,
+        };
+        item.hzDetail = {
+          hz_json: null,
         };
         getLogin(MethodName, data)
           .then((res) => {
             this.$set(item.hzDetail, "hz_json", res);
+            this.ShowHzData = JSON.parse(JSON.stringify(this.hzData));
             this.loading = false;
           })
           .catch(() => {
@@ -87,13 +151,16 @@ export default {
     if (this.$route.query.keyword) {
       let arr = this.$route.query.keyword.split("");
       arr.forEach((item) => {
+        let result = pinyinUtil.getPinyin(item);
         let obj = {
           con: item,
+          pinyin: result,
           hzDetail: {
             hz_json: null,
           },
         };
         this.hzData.push(obj);
+        this.ShowHzData = JSON.parse(JSON.stringify(this.hzData));
       });
       this.gethzJSON();
     }
@@ -121,19 +188,112 @@ export default {
 .result {
   height: 100%;
   .main {
-    height: 100%;
+    min-height: 100%;
     background: #f2f2f2;
     padding-top: 33px;
+    padding-bottom: 66px;
   }
   .hanzi_list {
     width: 1120px;
+    max-height: 858px;
     margin: 0 auto;
     background: #ffffff;
     border-radius: 8px;
     padding: 40px;
+
+    overflow-y: scroll;
+
+    .top_jf {
+      width: 128px;
+    }
+    .j_f {
+      display: flex;
+      width: 60px;
+      height: 24px;
+      margin-bottom: 16px;
+      margin-left: 33px;
+      > :nth-child(1) {
+        border-top-left-radius: 2px;
+        border-bottom-left-radius: 2px;
+        border-right: none;
+      }
+      > :nth-child(2) {
+        border-top-right-radius: 2px;
+        border-bottom-right-radius: 2px;
+        border-left: none;
+      }
+      div {
+        width: 30px;
+        height: 24px;
+        font-weight: 400;
+        font-size: 14px;
+        line-height: 24px;
+        text-align: center;
+        color: #de4444;
+        cursor: pointer;
+        border: 2px solid #de4444;
+      }
+      .sele {
+        color: #ffffff;
+        background: #de4444;
+      }
+    }
     .list_one {
       margin-bottom: 20px;
       display: flex;
+      align-items: flex-start;
+      .Highlight {
+        flex: 1;
+        margin-left: 22px;
+        display: flex;
+        flex-wrap: wrap;
+        .play_audio {
+          width: 100%;
+          display: flex;
+          align-items: center;
+          margin-bottom: 13px;
+          img {
+            width: 16px;
+            height: 16px;
+            cursor: pointer;
+          }
+          span {
+            font-family: "GB-PINYINOK-B";
+            font-weight: 400;
+            font-size: 12px;
+            margin-left: 5px;
+            color: #000000;
+          }
+        }
+      }
+      .row {
+        margin-right: 8px;
+        margin-bottom: 8px;
+        .number {
+          margin-top: 9px;
+          width: 64px;
+          height: 20px;
+          background: #e9e9e9;
+          border-radius: 22px;
+          text-align: center;
+          line-height: 20px;
+        }
+      }
+    }
+    .shouqi {
+      margin-top: 21;
+      display: flex;
+      justify-content: flex-end;
+      span {
+        cursor: pointer;
+        display: flex;
+        align-items: center;
+      }
+      img {
+        width: 24px;
+        height: 24px;
+        margin-right: 4px;
+      }
     }
   }
 }

部分文件因为文件数量过多而无法显示