个人练习程序
此文于2024年8月17日更新。
我不想和任何人说话,大家不要打扰我。
此页面程序自动排版有问题,一些程序被移到程序框外面了。下面一些内容会白屏几秒钟,可能因为程序框内容量太大。
unity游戏源码和教程:智能分析话语的三维唯美世界。
这个游戏的源码(含教程文档)我放到了夸克网盘https://pan.quark.cn/s/618fb9459029
小区:
小区傍晚的雪:
小区的晚上:
家里:
市中心:
市街道:
郊区:
(一)声明
小区场景的三维模型来自于UnityStore的unity包:Low Poly Japanese Housing Complex。很多人在用,所以我的游戏和其他人的游戏出现这个相同场景,不是抄袭。而且那只是个三维模型,程序要自己写,每个人写的程序是不同的。
市中心、市街道、郊区场景,来自UnityStore的unity包:258316_Anime_Tokyo_(Japanese_City),也有很多游戏开发者在用这个场景三维模型。
人物三维模型来自于网络上大家常见、常用的三维人物模型,我做了骨骼绑定、蒙皮、走路动画。
雪景程序来自于unity包:Global Snow,天空盒来自于unity包:AllSky。
(二)基本操作
W键(长按):向前走。
S键(长按):向后走。
A键(长按):向左转。
D键(长按):向右转。
鼠标左右上下移动来控制摄像机视角(屏幕视角),人物前进方向自动朝向摄像机视角。
键盘右边的方向键:上:抬高摄像机视角,下:降低摄像机视角,左:拉近摄像机视角,右:拉远摄像机视角。
F键(单击):第三人称视角和第一人称视角的切换。第三人称视角适合用在街上,第一人称视角适合用在家里。
空格键(单击):显示或关闭文字的输入输出框(默认不显示,需要点击空格键才显示)。输入完文字后,按回车键发送。
M键(单击):背景音乐,继续按,是下一首背景音乐。
数字键1(单击):小区场景(默认场景)。
数字键2(单击):市中心场景。
数字键3(单击):市街道场景。
数字键4(单击):郊区场景。
Esc键(单击):退出游戏。
小区场景中:
H键(单击):小区场景时,可以一键回家。
G键(单击),男主角和女主角分开,女主角停留在原地。男主角走远后,第二次按G键,女主角会自动寻路来找男主角,到男主角身边。
J键(单击):女主角一键换服装。
K键(单击):每点击一次,就变换一次天色。浅夜→夜晚→白天→傍晚→夜晚→清晨→白天→阴天。
L键(单击):正常景色和雪景的切换。
(三)
即便没有安装unity编辑器的情况下,play文件夹里DreamStart.exe可以直接运行此游戏。
unity的一份源码,只能适配一个编辑器版本,这个源码适配的是2022.3.38,其它版本打开此源码,会故障。
unity导入此项目时,不是导入哪个具体启动文件,而是用unity Hub(unity启动器)直接打开(导入)DreamStart文件夹。
如果unity编辑器没有显示场景,就在编辑器里手动打开park文件夹里的Scenes文件夹里的park场景文件即可。
在unity编辑器界面,不要把窗口最大化后再运行游戏,那样运行不了。但可以在游戏后,再最大化窗口。
地上的蓝色,是自动寻路烘培的地面,游戏运行时不显示那蓝色。
(四)话语分析
话语分析是有用的,假如游戏中,你是队长,带着NPC队友张三和李四,路上遇到蛇,你可以说“张三打蛇,李四保护张三。”这就需要先分析出主语、谓语、宾语,程序才能处理。
输入完成后,按回车键发送。
示例:
输入:猫吃鼠
显示:主语:猫,谓语动词:吃,宾语:鼠
输入:白色的猫吃黑色的鼠
显示:主语:猫,谓语动词:吃,宾语:鼠,主语的形容词:白色的,宾语的形容词:黑色的
输入:两只猫吃3只鼠
显示:主语:猫,谓语动词:吃,宾语:鼠,主语的数词:2只,宾语的数词:3只
输入:张三的猫吃李四的鼠
显示:主语:猫,谓语动词:吃,宾语:鼠,主语的名词所有格:张三,宾语的名词所有格:李四
输入:张三给李四苹果
显示:主语:张三,谓语动词:给,间接宾语:李四,直接宾语:苹果
输入:张三让李四打扫教室
显示:主语:张三,谓语动词:让,宾语:李四,宾语补足语动词:打扫,宾语补足语名词:教室
输入:2024年张三在学校吃饭
显示:主语:张三,谓语动词:吃饭,时间:2024年,地点:学校
如果分析显示不了,可能词语不在词库里。先找动词分割句子,再找名词,所以如果动词不在词库里,即便名词在词库里,也没用。
连接的单机数据库是garden.db,是sqlite单机数据库,就是在用户电脑的游戏文件里的,不联网的、不用安装服务的、不用配置的,直接就可以用的数据库。
(五)
人工智能分析话语的源码教程:
这仅是前六章,以后我还会继续写。用C#语言写的。如果找不出主语、谓语、宾语等,因为词语不在词库中,那就需要手动添加进词库。还有,先按动词分割句子,如果动词找不到,后面名词就算在词库,也找不到。目前词库里,名词7128个,动词5886个,形容词1777个。
每一章是在前一章的基础上增加内容,从而使读者能循序渐进的看懂。如果直接给个结果,读者不知道怎么一步步变化来的,那也就看不懂结果了。
前三章概述:
第一章的主要内容
判断输入的句子中,是否包含名词。
找出句子的主语、谓语、宾语。
解决三个基本问题
前面的方法,靠句子包含的词直接与词库的词对比,来找主语(名词)、谓语(动词)、宾语(名词),会有问题:
第一个问题:熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
所以创建一个函数:WordCover(覆盖)。
词语槽(WordBox)存放这些找到词,以实现覆盖和吸收。
第二个问题:熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
对于第二个问题的解决方法:
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
所以创建一个de函数。
第三个问题:“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge,词性辨析表在数据库里,已经做好了。
第二章的主要内容
基本单句有六种句型:
只有性质状态(表语):真漂亮、对啊、太好了。句子里没有谓语动词,其余五种句型里,都有谓语动词。
主语(动作执行者)-谓语(动作):张三摔倒。
主语(动作执行者)-谓语(动作)-宾语(动作对象):猫吃鼠。
主语-谓语(是)-表语(表明主语的身份和性质状态):张三是老师,太阳是美丽的。
双宾语句型:主语(传输的人)-谓语(传输动作)-间接宾语(传输对象)-直接宾语(传输的事物):张三给李四苹果,张三教李四数学。
宾语补足语句型:主语-谓语(例如把、使、让)-宾语-宾语补足语(做什么):张三让李四跳舞,张三把房间弄脏了。
前面只说了主谓宾句型,还要处理其它句型。
双宾语句型:
双宾语句型的谓语动词后面有两个名词,例如张三给李四苹果,李四是间接宾语(名词),苹果是直接宾语(名词)。
但是有两个名词的就是双宾语句型吗?不是的。例如张三喜欢足球学校。谓语动词后面有两个名词:足球、学校,但显然足球学校是一个整体名词,也就是主谓宾句型,而不是双宾语句型。因此判断双宾语句型,还要看谓语动词是不是适合双宾语句型的。
双宾语句型的谓语动词主要是传输事物的动词:给、送给、教。
那么谓语动词是双宾语句型的动词(例如给、教),且谓语动词后面有两个名词(体现为谓语动词右边的语句处理时,名词槽NounBox有两个名词,NounBox1和NounBox2都有值),就可以判断为双宾语句型。
还有,像“足球学校”这样两个名词连在一起,就要合并成一个名词,作为主语或宾语。
仅从双宾语句型的标志动词“教”判断双宾语句型,不一定准确,例如“他教我数学”是双宾语句型,但“他教书”就不是双宾语句型,所以还要根据宾语名词的数量,来判断到底是不是双宾语句型,如果动词右边只有一个名词,例如“他教书”的“书”,句子就不是双宾语句型。所以通过谓语动词判断一个句子是双宾语句型后,根据找到的名词数量,例如只有一个宾语名词,那么就要把双宾语句型,修正回主谓宾句型。
名词次序:间接宾语在直接宾语之前,所以找到两个名词,次序在前面的那个名词,是间接宾语,次序在后面的那个名词是直接宾语。
宾语补足语句型:
和主谓宾句型不同,宾语补足语句型含有主谓宾句型的部分,但宾语后面还有个动作(动词),也就是宾语补足语。
因此看宾语后面是否还有动词,是判断宾语补足语句型的方法。
但是有两个动词就麻烦了,如何判断这个动词是谓语动词还是宾语补足语动词呢?那就需要先把所有动词找出来,如果是宾语补足语动词,那么这个动词在谓语动词的后面,如果是谓语动词,则在前面。
既然要存放多个动词进行判断,就要有动词槽(VerbBox)。
动词次序:谓语动词在宾语补足语动词之前,所以找到两个动词,词语次序在前面的是谓语动词,词语次序在后面的是宾语补足语动词。
宾语补足语动词后面还有个名词,宾语补足语动词和这个名词合并在一起,作为宾语补足语。例如他让我打扫教室。如果宾语补足语只是“打扫”,话就说不清楚了。但是有些宾语补足语,就只有动词,后面没有名词,例如“他让我跳舞”就只有“跳舞”这一个动词,“跳舞”这个词后面没有名词,因为“跳舞”是不及物动词。
双宾语句型和宾语补足语句型,都是由主谓宾句型拓展而成的。双宾语句型在主谓宾句型的基础上,多加了一个宾语。宾语补足语句型在主谓宾句型的基础上,多加了一个动词(宾语补足语)。所以先完成主谓宾句型,再根据是否有拓展,来判断是不是双宾语句型或宾语补足语句型。
第三章的主要内容
省略主语有两种情况:一种是主动语态省略主语,例如“跳过去”,全句指“你跳过去”。另一种是被动语态省略主语,例如“张三被打了”,没说谁打了张三,这里张三是宾语。如果说“李四打了张三”,李四就是主语。
被动语态的标志是“被”字,如果没有“被”字,而且省略了主语,就是主动语态省略主语的情况,那么这种情况下,主语应该填什么呢?例如“过来”,一般指“你过来”,但“走吧”一般指“我们走吧”。所以程序要根据具体的动词来判断省略的主语应该填什么。但是动词太多,每个动词都要设置省略的主语判断,太麻烦。所以省略主语,按最通常情况,就默认填“你”字,作为主语。如果主语是“我们”而不是“你”字,就不该省略主语。
被动语态应该还原为主动语态去理解,但被动语态往往没有主语,那么默认主语应该填什么呢?毕竟不知道主语,那就填“事物”这个词作为主语。
程序分析句子时,被动语态的主语位置的词,是宾语。例如“李四被打了”,李四在谓语动词左边句,程序会把李四当成主语,但在被动语态句里,李四不是主语,所以有“被”字的时候,主语要挪动到宾语位置,然后在主语位置补充“事物”这个词,作为主语。
但是有些时候,被动语态的主语是说明了的,例如“李四被张三打了”就还原为主动语态“张三打了李四”,张三做主语,而不是填“事物”做主语。
简而言之,被动语态里,主语放到了宾语位置,宾语放到了主语位置,所以变为主动语态时,要把宾语挪回主语位置,主语挪回宾语位置。
如果被动语态有主语,例如“李四被张三打了”,那么主语(张三)位于“被”字与谓语动词之间。
那么谓语动词左边句中,又分为“被”字左边句和“被”字右边句,被字左边句里的名词是宾语,被字右边句里的名词是主语。
名词合并:
名词合并:例如“足球学校”这个词,会被当成两个名词“足球”和“学校”。但实际中,要把它们合并成一个组合名词,作为主语或宾语。
合并方法:如果两个字符(词语)是连续的,那么这两个词语之间的内容为空。
动词合并:
例如“应该爱”是两个动词:情态动词“应该”和普通动词“爱”,应该合并成一个动词。
动词前面是否有否定词,也很重要。
例如“他爱猫”和“他不爱猫”,虽然谓语动词都是“爱”字,但前面加个“不”字,意义就相反了。所以看谓语动词前面是否有否定词,是很重要的事。
谓语动词前面的否定词,一般有不、不要、不可以、不应该、不能、别。
还有不确定肯定还是否定动词,例如“他不一定去”,“去”字是动词,但是动词前的“不一定”,并不像是“不”字那样对动词进行否定,而是对动词既不像是肯定,也不像是否定,而是不确定。
因此对每句话的谓语动词,都要加一个性质:肯定、否定、不确定。
但不确定,有时候偏向于肯定,例如“他可能去”。有时候不确定偏向于否定,例如“他不太可能去”以及“他或许不去”。
那么动词发生概率分为五种:肯定、偏向肯定、不确定、偏向否定、否定。
这其实就是在分析事情(谓语动词)发生的概率,这在概率分析上有用。
第五章:
对于数词,之前用正则表达式直接抽取出数字,那种方法太简单了,我用逐字分析的方法重写了。
还有就是分析出时间,不仅分析出是年、月、日、时、分,还要分析出一些时间词:
"今天", "明天", "后天", "昨天", "前天", "这个月", "下个月", "上个月", "今年", "明年", "去年"
"早晨", "上午", "中午", "下午", "傍晚", "晚上", "傍晚", "夜晚", "半夜", "黎明", "黄昏", "清晨"
"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日", "礼拜一", "礼拜二", "礼拜三", "礼拜四", "礼拜五", "礼拜六", "礼拜天"
"春天", "夏天", "秋天", "冬天", "春季", "夏季", "秋季", "冬季"
"元旦", "大年三十", "除夕", "春节", "大年初一", "大年初二", "大年初三", "正月十五", "寒假", "清明节", "五一节", "劳动节", "儿童节", "暑假", "中秋节", "国庆节", "圣诞节", "假期", "休息日"
第五章可用的动词单位是:
"个", "名", "位", "只", "头", "匹", "条", "棵", "朵", "片", "根", "座", "栋", "台", "部", "本", "块", "件", "盏", "把", "所", "辆", "艘", "架", "扇"
"米", "厘米", "毫米", "分米", "公里", "里", "微米", "纳米", "克", "斤", "公斤", "吨", "毫克", "升"
先找到动词单位,才能找到数词。
第六章:
直接宾语的定语(形容词、数词、名词所有格),在间接宾语和直接宾语之间。
例如张三给李四红色的苹果,李四是间接宾语,苹果是直接宾语,红色的是形容词。
间接宾语的定语在谓语动词和间接宾语之间,对于谓语动词右边句,也就是句子开始到间接宾语之间。
例如张三给美丽的李四苹果,李四是间接宾语,美丽的是形容词。
宾语补足语名词的定语(形容词、数词、名词所有格)在宾语补足语动词的右边。
例如张三让李四打扫蓝色的房子,打扫是宾语补足语的动词,房间是宾语补足语的名词,蓝色的是形容词。
第六章增加了猜测词语的功能,但不建议用猜测词语,因为如果一个词语,词库里没有,要靠程序猜测,那么游戏剧情肯定对这个词语没做任何准备,就算猜测出这个词,也没用。
例如张三爱雅娜,名词词库肯定没有“雅娜”这个词,但是谓语动词“爱”字右边的句子的两个字,显然是宾语名词,所以猜测词语是很容易猜测的。
就算猜测出宾语是雅娜,又怎样了呢,对雅娜的信息和属性,什么都没有设置,程序没法分析。甚至连雅娜到底是一个人还是一块石头,都没法分析。
那么张三带着雅娜去海边,到底是张三带着女人雅娜去海边,还是张三带着石头雅娜去海边,准备扔石头玩水漂。计算机分析程序一头雾水,所以猜测词语会降低计算机的分析能力。
还是勤快点吧,把词语录入词库,并给词语设置信息和属性。什么时候用猜测词语呢?词库词汇量还不够多的时候,只能靠猜词来补偿,但这不是长远的办法。
这就好比编程强调“对变量,要先定义,后使用”,猜测词语就好比不定义就直接使用。
猜测词语的原理:抽取掉已知的词语(词库里有的词语),剩下的未知的词语(词库里没有的词语),就是要猜测的词。
例如“张三喜欢美丽的雅娜”,谓语动词右边句是“美丽的雅娜”,词库已有的形容词是“美丽的”,抽取掉形容词“美丽的”,剩下的词语“雅娜”就是要猜测的宾语。
第一章
人工智能处理语言的意义
假如你是队长,带着两个NPC队友张三和李四,路上遇到一条蛇。你下令张三打蛇,李四保护张三,这就需要先分析出句子的主语、谓语、宾语,程序才能操作命令。
单机数据库的意义
这个程序用的是单机数据库sqlite,单机游戏一般都用单机数据库sqlite。因为一方面,单机数据库不联网,在用户电脑的游戏文件里,而不是在服务器上。另一方面,单机数据库不用安装服务,不用做配置,用户啥都不用管,直接就能用。
需要的插件说明
有词库的sqlite数据库garden.db。其中名词表noun,名词列word_col。动词表verb,动词列word_col。还有词性辨析表verb_judge。
把garden.db放到Assets文件夹的上一级文件夹,也就是程序源码的根目录,就可以在编辑器环境下运行了。生成游戏后,garden.db还要复制到生成游戏的文件夹里。
将C盘→Program Files→Unity→Hub→Editor→2022.3.38→Editor→Data→MoonBleedingEdge→lib→mono→net_4_x-win32文件夹里的Mono.data.sqlite.dll和system.data.dll放到Plugins文件夹里(在Assets文件夹里,自己创建一个Plugins文件夹,字母P大写,系统自动认为那是个存放插件的文件夹)。
在sqlite官网下载sqlite3.dll也放到Plugins文件夹里。
Mono.data.sqlite.dll、system.data.dl、sqlite3.dll是sqlite数据库运行所需的三个插件。
判断输入的句子中,是否包含名词
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Mono.Data.Sqlite;
public class sqlitecon : MonoBehaviour
{
public TMP_Text tmpText;//输出框对象
string ShowText;//输出框的内容
string[] noun = new string[7128];//名词数组,名词数量7128
string[] verb = new string[5886];//动词数组,动词数量5886
int i = 0;//数组用的循环变量
public TMP_InputField inputField;//输入框对象
// Start is called before the first frame update
void Start()
{
//inputField = GetComponent<TMP_InputField>();//输入框获取组件
inputField.onEndEdit.AddListener(OnInputEndEdit);//输入完成后,对回车键的响应
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
string sqlQuery = "SELECT word_col FROM noun";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充名词数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
while (dbReader.Read())
{
noun[i] = dbReader.GetValue(0).ToString();//GetValue(0)表示结果集的第一列,因为只查询了一列,所以返回的结果集就一列
i++;
}
dbReader.Close();
UnityEngine.Debug.Log(i);//显示名词数量
//填充动词数组
//第一步:sql指令
sqlQuery = "SELECT word_col FROM verb";//sql指令
//第二步:执行指令
//dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充动词数组
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
verb[i] = dbReader.GetValue(0).ToString();
i++;
}
dbReader.Close();
UnityEngine.Debug.Log(i);//显示动词数量
}
// Update is called once per frame
void Update()
{
}
void OnInputEndEdit(string value)
{
string shuru = inputField.text;//输入框的值
string jieguo = "不包含";//默认值是不包含
int m = noun.Length;//名词数组的长度,也就是有多少个名词
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和名词的包含关系
就是用句子和名词数组的名词,一一比对,来判断是否包含名词
n的值从0逐渐增长到名词数组的名词数量值,这样数组也就经历了所有名词
*/
if (shuru.Contains(noun[n]))//包含
{
jieguo = "包含";
}
}
tmpText.text = jieguo;//显示结果
}
}
OnInputEndEdit函数里,稍微改变一下,也可以用于找动词。
找出句子的主语、谓语、宾语
例如输入:白色的猫吃黑色的鼠。主语显示:猫,谓语动词显示:吃,宾语显示:鼠。
基本原理:对于主谓宾句型,先找出动词,然后以动词为分割符号,分割句子。动词左边分割出的句子的名词就是主语,动词右边分割出的句子的名词就是宾语。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Mono.Data.Sqlite;
public class sqlitecon : MonoBehaviour
{
public TMP_Text tmpText;//输出框对象
string ShowText;//输出框的内容
string[] noun = new string[7128];//名词数组,名词数量7128
string[] verb = new string[5886];//动词数组,动词数量5886
int i = 0;//数组用的循环变量
public TMP_InputField inputField;//输入框对象
string shuru = "";//输入框的内容
string FindSubject = "";//找到的主语
string FindVerb = "";//找到的谓语动词
string FindObject = "";//找到的宾语
// Start is called before the first frame update
void Start()
{
inputField.onEndEdit.AddListener(OnInputEndEdit);//输入完成后,对回车键的响应
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
string sqlQuery = "SELECT word_col FROM noun";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充名词数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
while (dbReader.Read())
{
noun[i] = dbReader.GetValue(0).ToString();//GetValue(0)表示结果集的第一列,因为只查询了一列,所以返回的结果集就一列
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示名词数量
//填充动词数组
//第一步:sql指令
sqlQuery = "SELECT word_col FROM verb";//sql指令
//第二步:执行指令
//dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充动词数组
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
verb[i] = dbReader.GetValue(0).ToString();
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示动词数量
}
// Update is called once per frame
void Update()
{
}
void OnInputEndEdit(string value)
{
shuru = inputField.text;//输入框的值
//找谓语动词
string jieguo = "不包含";//默认值是不包含
int m = verb.Length;//动词数组的长度,也就是有多少个动词
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和动词的包含关系
就是用句子和动词数组的动词,一一比对,来判断是否包含动词
n的值从0逐渐增长到动词数组的动词数量值,这样数组也就经历了所有动词
*/
if (shuru.Contains(verb[n]))//包含
{
jieguo = "包含";
FindVerb = verb[n];//找到了动词
}
}
if(jieguo == "包含")
{
SplitSentence(FindVerb);
}
//tmpText.text = jieguo;//显示结果
}
void SplitSentence(string find_verb)
{
/*
对于主谓宾句型,先找出动词,然后以动词为分割符号,分割句子。动词左边分割出的句子的名词就是主语,动词右边分割出的句子的名词就是宾语
先举个例子简单说明一下字符串分割的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "吃";//指定词
string res = "";//结果
int chang = 0;//全句长度
int index = 0;//指定词的位置(索引)
int i = 0;//临时变量
int j = 0;//临时变量
//计算全句长度
chang = str.Length;//显示字符个数,从1开始计算
UnityEngine.Debug.Log(chang);//显示9
//计算指定字符在全句中的位置
index = str.IndexOf(word);//从0计算,例如第2个字符,显示为1,而不是2
UnityEngine.Debug.Log(index);//显示4
//截取第3个字符右边的1个字符
Substring(开始位置,向右截取长度),从1开始计算,不是0
res = str.Substring(3,1); //从第3个字符开始,向右截取1个字符
UnityEngine.Debug.Log(res);//显示:猫
//截取指定字符右边的全部字符
i = index + 1;//指定字符的位置,由于index是从0开始计算的,所以要加1,变为从1开始计算的方式,所以是index+1
j = chang - (index + 1);//截取长度 = 全句长度 - 指定字符的位置长度
UnityEngine.Debug.Log(i);//显示5
UnityEngine.Debug.Log(chang);//显示9
UnityEngine.Debug.Log(j);//显示4
res = str.Substring(i,j);
UnityEngine.Debug.Log(res);//显示:黑色的鼠
res = str.Substring(index + 1, chang - (index + 1));//变化形式
UnityEngine.Debug.Log(res);//显示:黑色的鼠
//index变为str.IndexOf(word),chang变为str.Length
res = str.Substring(str.IndexOf(word) + 1, str.Length - (str.IndexOf(word) + 1));//变化形式
UnityEngine.Debug.Log(res);//显示:黑色的鼠
//截取指定字符左边的全部字符
res = str.Substring(0,index);//从句子开始的0位置,截取长度是指定字符的位置长度
res = str.Substring(0,str.IndexOf(word));//变化形式
UnityEngine.Debug.Log(res);//显示:白色的猫
//截取两个指定字符之间的全部字符
i = str.IndexOf("猫");
j = str.IndexOf("鼠");
res = str.Substring(i+1,j-(i+1));
UnityEngine.Debug.Log(res);//显示:吃黑色的
//把i变为str.IndexOf("猫"),j变为str.IndexOf("鼠")
res = str.Substring(str.IndexOf("猫") + 1, str.IndexOf("鼠") - (str.IndexOf("猫") + 1));//变化形式
UnityEngine.Debug.Log(res);//显示:吃黑色的
//数组形式截取字符
//前面定义了:str = "白色的猫吃黑色的鼠"; word = "吃";
string[] shuzu = str.Split(word);//按指定分割符分割字符串,并存入数组中
UnityEngine.Debug.Log(shuzu[0]);//显示:白色的猫
UnityEngine.Debug.Log(shuzu[1]);//显示:黑色的鼠
//或逐一显示数组全部
foreach (string part in shuzu)
{
UnityEngine.Debug.Log(part);
}
*/
string LeftPart = "";//谓语动词的左边句
string RightPart = "";//谓语动词的右边句
LeftPart = shuru.Substring(0, shuru.IndexOf(find_verb));
RightPart = shuru.Substring(shuru.IndexOf(find_verb) + 1, shuru.Length - (shuru.IndexOf(find_verb) + 1));
/*
例如句子(shuru)是白色的猫吃黑色的鼠
find_word:吃
LeftPart:白色的猫
RightPart:黑色的鼠
UnityEngine.Debug.Log(find_verb);
UnityEngine.Debug.Log(LeftPart);
UnityEngine.Debug.Log(RightPart);
*/
if (find_verb != "")
{
FindVerb = find_verb;
}
if (LeftPart != "")
{
FindSubject = SearchNoun(LeftPart);//找名词
}
if (RightPart != "")
{
FindObject = SearchNoun(RightPart);//找名词
}
UnityEngine.Debug.Log(FindSubject);
UnityEngine.Debug.Log(FindVerb);
UnityEngine.Debug.Log(FindObject);
}
string SearchNoun(string PartSentence)
{
//找名词
string jieguo = "不包含";//默认值是不包含
string FindNoun = "";//要找的名词
int m = noun.Length;//名词数组的长度,也就是有多少个名词
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和名词的包含关系
就是用句子和名词数组的名词,一一比对,来判断是否包含名词
n的值从0逐渐增长到名词数组的名词数量值,这样数组也就经历了所有名词
*/
if (PartSentence.Contains(noun[n]))//包含
{
jieguo = "包含";
FindNoun = noun[n];//找到了名词
}
}
if (jieguo == "包含")
{
return FindNoun;
}
else
{
return "";
}
}
}
解决三个基本问题
前面的方法,靠句子包含的词直接与词库的词对比,来找主语(名词)、谓语(动词)、宾语(名词),会有问题:
第一个问题:熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
所以创建一个函数:WordCover(覆盖)。
词语槽(WordBox)存放这些找到词,以实现覆盖和吸收。
第二个问题:熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
对于第二个问题的解决方法:
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
所以创建一个de函数。
第三个问题:“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge,词性辨析表在数据库里,已经做好了。
+--------------+-------------+----------------+
| word_col | type_col | content_col |
+--------------+-------------+----------------+
| 学 | r1 | 生 |
+--------------+-------------+----------------+
| 压 | l1 | 气 |
+--------------+-------------+----------------+
word_col:判断这个字是动词还是名词。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
所以创建一个VerbJudge函数。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Mono.Data.Sqlite;
public class sqlitecon : MonoBehaviour
{
public TMP_Text tmpText;//输出框对象
string ShowText;//输出框的内容
string[] noun = new string[7128];//名词数组,名词数量7128
string[] verb = new string[5886];//动词数组,动词数量5886
int i = 0;//数组用的循环变量
public TMP_InputField inputField;//输入框对象
string shuru = "";//输入框的内容
string FindSubject = "";//找到的主语
string FindVerb = "";//找到的谓语动词
string FindObject = "";//找到的宾语
string WordBox1 = "";//词语槽1
string WordBox2 = "";//词语槽2
string WordBox3 = "";//词语槽3
string WordBox4 = "";//词语槽4
// Start is called before the first frame update
void Start()
{
inputField.onEndEdit.AddListener(OnInputEndEdit);//输入完成后,对回车键的响应
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
string sqlQuery = "SELECT word_col FROM noun";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充名词数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
while (dbReader.Read())
{
noun[i] = dbReader.GetValue(0).ToString();//GetValue(0)表示结果集的第一列,因为只查询了一列,所以返回的结果集就一列
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示名词数量
//填充动词数组
//第一步:sql指令
sqlQuery = "SELECT word_col FROM verb";//sql指令
//第二步:执行指令
//dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充动词数组
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
verb[i] = dbReader.GetValue(0).ToString();
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示动词数量
dbConnection.Close();
}
// Update is called once per frame
void Update()
{
}
void OnInputEndEdit(string value)
{
shuru = inputField.text;//输入框的值
//找谓语动词
string jieguo = "不包含";//默认值是不包含
int m = verb.Length;//动词数组的长度,也就是有多少个动词
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和动词的包含关系
就是用句子和动词数组的动词,一一比对,来判断是否包含动词
n的值从0逐渐增长到动词数组的动词数量值,这样数组也就经历了所有动词
*/
if (shuru.Contains(verb[n]))//包含
{
if (VerbJudge(shuru,verb[n]) == true)
{
jieguo = "包含";
FindVerb = verb[n];//找到了动词
}
}
}
if(jieguo == "包含")
{
SplitSentence(FindVerb);
}
//tmpText.text = jieguo;//显示结果
}
void SplitSentence(string find_verb)
{
/*
对于主谓宾句型,先找出动词,然后以动词为分割符号,分割句子。动词左边分割出的句子的名词就是主语,动词右边分割出的句子的名词就是宾语
先举个例子简单说明一下字符串分割的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "吃";//指定词
string res = "";//结果
int chang = 0;//全句长度
int index = 0;//指定词的位置(索引)
int i = 0;//临时变量
int j = 0;//临时变量
//计算全句长度
chang = str.Length;//显示字符个数,从1开始计算
UnityEngine.Debug.Log(chang);//显示9
//计算指定字符在全句中的位置
index = str.IndexOf(word);//从0计算,例如第2个字符,显示为1,而不是2
UnityEngine.Debug.Log(index);//显示4
//截取第3个字符右边的1个字符
Substring(开始位置,向右截取长度),从1开始计算,不是0
res = str.Substring(3,1); //从第3个字符开始,向右截取1个字符
UnityEngine.Debug.Log(res);//显示:猫
//截取指定字符右边的全部字符
i = index + 1;//指定字符的位置,由于index是从0开始计算的,所以要加1,变为从1开始计算的方式,所以是index+1
j = chang - (index + 1);//截取长度 = 全句长度 - 指定字符的位置长度
UnityEngine.Debug.Log(i);//显示5
UnityEngine.Debug.Log(chang);//显示9
UnityEngine.Debug.Log(j);//显示4
res = str.Substring(i,j);
UnityEngine.Debug.Log(res);//显示:黑色的鼠
res = str.Substring(index + 1, chang - (index + 1));//变化形式
UnityEngine.Debug.Log(res);//显示:黑色的鼠
//index变为str.IndexOf(word),chang变为str.Length
res = str.Substring(str.IndexOf(word) + 1, str.Length - (str.IndexOf(word) + 1));//变化形式
UnityEngine.Debug.Log(res);//显示:黑色的鼠
//截取指定字符左边的全部字符
res = str.Substring(0,index);//从句子开始的0位置,截取长度是指定字符的位置长度
res = str.Substring(0,str.IndexOf(word));//变化形式
UnityEngine.Debug.Log(res);//显示:白色的猫
//截取两个指定字符之间的全部字符
i = str.IndexOf("猫");
j = str.IndexOf("鼠");
res = str.Substring(i+1,j-(i+1));
UnityEngine.Debug.Log(res);//显示:吃黑色的
//把i变为str.IndexOf("猫"),j变为str.IndexOf("鼠")
res = str.Substring(str.IndexOf("猫") + 1, str.IndexOf("鼠") - (str.IndexOf("猫") + 1));//变化形式
UnityEngine.Debug.Log(res);//显示:吃黑色的
//数组形式截取字符
//前面定义了:str = "白色的猫吃黑色的鼠"; word = "吃";
string[] shuzu = str.Split(word);//按指定分割符分割字符串,并存入数组中
UnityEngine.Debug.Log(shuzu[0]);//显示:白色的猫
UnityEngine.Debug.Log(shuzu[1]);//显示:黑色的鼠
//或逐一显示数组全部
foreach (string part in shuzu)
{
UnityEngine.Debug.Log(part);
}
*/
string LeftPart = "";//谓语动词的左边句
string RightPart = "";//谓语动词的右边句
LeftPart = shuru.Substring(0, shuru.IndexOf(find_verb));
RightPart = shuru.Substring(shuru.IndexOf(find_verb) + 1, shuru.Length - (shuru.IndexOf(find_verb) + 1));
/*
例如句子(shuru)是白色的猫吃黑色的鼠
find_word:吃
LeftPart:白色的猫
RightPart:黑色的鼠
UnityEngine.Debug.Log(find_verb);
UnityEngine.Debug.Log(LeftPart);
UnityEngine.Debug.Log(RightPart);
*/
if (find_verb != "")
{
FindVerb = find_verb;
}
if (LeftPart != "")
{
FindSubject = SearchNoun(LeftPart);//找名词
}
if (RightPart != "")
{
FindObject = SearchNoun(RightPart);//找名词
}
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("宾语:" + FindObject);
/*
靠句子包含的词直接与词库的词对比,来找主语(名词)、谓语(动词)、宾语(名词),会有问题:
第一个问题:熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
所以创建一个函数:WordCover(覆盖)。
词语槽(WordBox)存放这些找到词,以实现覆盖和吸收。
第二个问题:熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
对于第二个问题的解决方法:
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
所以创建一个de函数。
第三个问题:“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+--------------+-------------+----------------+
| word_col | type_col | content_col |
+--------------+-------------+----------------+
| 学 | r1 | 生 |
+--------------+-------------+----------------+
| 压 | l1 | 气 |
+--------------+-------------+----------------+
word_col:判断这个字是动词还是名词。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
所以创建一个VerbJudge函数。
*/
}
string SearchNoun(string PartSentence)
{
//找名词
string jieguo = "不包含";//默认值是不包含
string FindNoun = "";//要找的名词
int m = noun.Length;//名词数组的长度,也就是有多少个名词
//for循环前,先把词语槽清空,因为for循环时,调用的函数WordCover要用词语槽,来完成词语的覆盖和吸收
WordBox1 = "";
WordBox2 = "";
WordBox3 = "";
WordBox4 = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和名词的包含关系
就是用句子和名词数组的名词,一一比对,来判断是否包含名词
n的值从0逐渐增长到名词数组的名词数量值,这样数组也就经历了所有名词
*/
if (PartSentence.Contains(noun[n]))//包含
{
jieguo = "包含";
//FindNoun = noun[n];//找到了名词
if (de(PartSentence, noun[n]) == false)//找到的名词右边的第一个字符不是“的”字
{
FindNoun = WordCover(noun[n]);
}
}
}
if (jieguo == "包含")
{
return FindNoun;
}
else
{
return "";
}
}
string WordCover(string FindWord)
{
/*
熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
词语槽(WordBox)存放这些找到词,以实现覆盖和吸收。
做了4个词语槽(WordBox),为了以后适应复杂的句子,但简单的主谓宾句型,一个词语槽就够了。
*/
if (WordBox1 == "" && FindWord != "")//词语槽还是空的,说明这是找到的第一个词
{
WordBox1 = FindWord;//找到的第1个词,放入词语槽
FindWord = "";//置空,免得填到词语槽2了
}
else if (WordBox1 != "" && FindWord != "")//词语槽1已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(WordBox1))//覆盖:例如找到的词(FindWord)是熊猫,词语槽1(WordBox1)的词是熊,“熊猫”包含(Contain)“熊”字
{
WordBox1 = FindWord;//词语槽1的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽2了
}
else if (WordBox1.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽1(WordBox1)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,不要这个词了,免得填到词语槽2了
}
}
if (WordBox2 == "" && FindWord != "")//词语槽2是空的,FindWord经过词语槽1,没有覆盖或吸收,说明FindWord和词语槽1的词无关,例如FindWord是竹子
{
WordBox2 = FindWord;//找到的第2个词,放入词语槽
FindWord = "";//置空,免得填到词语槽3了
}
else if (WordBox2 != "" && FindWord != "")//词语槽2已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(WordBox2))//覆盖:例如找到的词(FindWord)是熊猫,词语槽2(WordBox2)的词是熊,“熊猫”包含(Contain)“熊”字
{
WordBox2 = FindWord;//词语槽2的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽3了
}
else if (WordBox2.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽2(WordBox2)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽3了
}
}
if (WordBox3 == "" && FindWord != "")//词语槽3是空的,FindWord经过词语槽2,没有覆盖或吸收,说明FindWord和词语槽2的词无关,例如FindWord是竹子
{
WordBox3 = FindWord;//找到的第3个词,放入词语槽
FindWord = "";//置空,免得填到词语槽4了
}
else if (WordBox3 != "" && FindWord != "")//词语槽3已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(WordBox3))//覆盖:例如找到的词(FindWord)是熊猫,词语槽3(WordBox3)的词是熊,“熊猫”包含(Contain)“熊”字
{
WordBox3 = FindWord;//词语槽3的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽4了
}
else if (WordBox3.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽3(WordBox3)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽4了
}
}
if (WordBox4 == "" && FindWord != "")//词语槽4是空的,FindWord经过词语槽3,没有覆盖或吸收,说明FindWord和词语槽3的词无关,例如FindWord是竹子
{
WordBox4 = FindWord;//找到的第4个词,放入词语槽
FindWord = "";//置空
}
else if (WordBox4 != "" && FindWord != "")//词语槽4已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(WordBox4))//覆盖:例如找到的词(FindWord)是熊猫,词语槽4(WordBox4)的词是熊,“熊猫”包含(Contain)“熊”字
{
WordBox4 = FindWord;//词语槽4的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空
}
else if (WordBox4.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽4(WordBox4)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空
}
}
return WordBox1;//对于主谓宾结构,找主语时,找到的名词只有一个,找宾语时,找到的名词也只有一个,所以只返回WordBox1
}
bool de(string str,string word)
{
/*
熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
UnityEngine.Debug.Log(res);//显示:的
以上内容是解释原理,下面是运行程序:
*/
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLastChar = str.IndexOf(word) + word.Length;
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
if (res == "的")
{
return true;
}
else
{
return false;
}
}
bool VerbJudge(string str,string word)
{
/*
“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+--------------+-------------+----------------+
| word_col | type_col | content_col |
+--------------+-------------+----------------+
| 学 | r1 | 生 |
+--------------+-------------+----------------+
| 压 | l1 | 气 |
+--------------+-------------+----------------+
word_col:判断这个字是动词还是名词,也就是辨析字。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。
“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
不容易理解的一处:
+--------------+-------------+----------------+
| word_col | type_col | content_col |
+--------------+-------------+----------------+
| 吹 | l1 | 电 |
+--------------+-------------+----------------+
“吹”字本身做动词,但在“电吹风”这个词里做名词,但我不用把“电吹风”这个三个字都判断,我只要判断“电吹”两个字就可以了。
遇到单字动词的时候,先看这个字是否在词性辨析表里,
如果在,type_col要求是r1(right1,就是要辨析的字的右边1个字符),那就看句子中要辨析的字的右边1个字符是不是符合词性表中的字,
如果符合,要辨析的字就是名词,而不是动词了。
例如学生看书,这句话先找到了动词“学”,在词性辨析表里,“学”字的type_col是r1,content_col是“生”字,
那就在句子中,看“学”字右边的1个字符是不是“生”字,如果是,“学”字就不做动词,而做名词了。
一个要辨析的字,type_col有四种可能:r1、r2、l1、l2,也就是右边1个字,右边2个字,左边1个字,左边2个字,那就要会四个方法:
符合r1:找辨析字右边1个字符:res = str.Substring(str.IndexOf(word) + word.Length, 1);
符合r2:找辨析字右边2个字符:res = str.Substring(str.IndexOf(word) + word.Length, 2);
符合l1:找辨析字左边1个字符:res = str.Substring(str.IndexOf(word) - 1, 1);
符合l2:找辨析字左边2个字符:res = str.Substring(str.IndexOf(word) - 2, 1);
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
res = str.Substring(str.IndexOf(word) + word.Length, 1);//变化形式
}
UnityEngine.Debug.Log(res);//显示:的
//指定词语左边1个字符
res = str.Substring(index - 1, 1);
res = str.Substring(str.IndexOf(word) - 1, 1);//变化形式
UnityEngine.Debug.Log(res);//显示:吃
以上内容是解释原理,下面是运行程序:
*/
string[] TypeCol = new string[100];//把词性辨析表的辨析字对应的type_col值填充此数组
string[] ContentCol = new string[100];//把词性辨析表的辨析字对应的content_col值填充此数组
string res = "";//截取的字符
bool shima = true;//默认判断是动词
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
//字符型变量要有引号,数字型变量不需要引号
//word是变量,动态的,不能直接放到sql语句里面
string sqlQuery = "select type_col,content_col from verb_judge where word_col = '" + word + "'";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充词性辨析数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
//查询了2列(type_col和content_col),所以返回的结果集有2列,分别用GetValue(0)和GetValue(1)
TypeCol[i] = dbReader.GetValue(0).ToString();//返回的结果集的第1列
ContentCol[i] = dbReader.GetValue(1).ToString();//返回的结果集的第2列
i++;//虽然定义数组长度为10,但i不一定填满了10
}
dbReader.Close();
dbConnection.Close();
if (i > 0)//在词性辨析表里找到内容了,否则i还是默认的0
{
for (int n = 0; n < i; n++)//遍历词性辨析表找到的各种结果
{
if (TypeCol[n] == "r1")//right1:右边1个字符
{
if (str.IndexOf(word) + word.Length + 1 <= str.Length)//要往右判断1个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 1);//截取动词右边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "r2")//right2:右边2个字符
{
if (str.IndexOf(word) + word.Length + 2 <= str.Length)//要往右判断2个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 2);//截取动词右边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l1")//left1:左边1个字符
{
if (str.IndexOf(word) - 1 >= 0)//要往左判断1个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 1, 1);//截取动词左边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l2")//left2:左边2个字符
{
if (str.IndexOf(word) - 2 >= 0)//要往左判断2个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 2, 2);//截取动词左边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
}
}
i = 0;
return shima;
}
}
第二章
基本单句有六种句型:
只有性质状态(表语):真漂亮、对啊、太好了。句子里没有谓语动词,其余五种句型里,都有谓语动词。
主语(动作执行者)-谓语(动作):张三摔倒。
主语(动作执行者)-谓语(动作)-宾语(动作对象):猫吃鼠。
主语-谓语(是)-表语(表明主语的身份和性质状态):张三是老师,太阳是美丽的。
双宾语句型:主语(传输的人)-谓语(传输动作)-间接宾语(传输对象)-直接宾语(传输的事物):张三给李四苹果,张三教李四数学。
宾语补足语句型:主语-谓语(例如把、使、让)-宾语-宾语补足语(做什么):张三让李四跳舞,张三把房间弄脏了。
前面只说了主谓宾句型,还要处理其它句型。
双宾语句型:
双宾语句型的谓语动词后面有两个名词,例如张三给李四苹果,李四是间接宾语(名词),苹果是直接宾语(名词)。
但是有两个名词的就是双宾语句型吗?不是的。例如张三喜欢足球学校。谓语动词后面有两个名词:足球、学校,但显然足球学校是一个整体名词,也就是主谓宾句型,而不是双宾语句型。因此判断双宾语句型,还要看谓语动词是不是适合双宾语句型的。
双宾语句型的谓语动词主要是传输事物的动词:给、送给、教。
那么谓语动词是双宾语句型的动词(例如给、教),且谓语动词后面有两个名词(体现为谓语动词右边的语句处理时,名词槽NounBox有两个名词,NounBox1和NounBox2都有值),就可以判断为双宾语句型。
还有,像“足球学校”这样两个名词连在一起,就要合并成一个名词,作为主语或宾语。
仅从双宾语句型的标志动词“教”判断双宾语句型,不一定准确,例如“他教我数学”是双宾语句型,但“他教书”就不是双宾语句型,所以还要根据宾语名词的数量,来判断到底是不是双宾语句型,如果动词右边只有一个名词,例如“他教书”的“书”,句子就不是双宾语句型。所以通过谓语动词判断一个句子是双宾语句型后,根据找到的名词数量,例如只有一个宾语名词,那么就要把双宾语句型,修正回主谓宾句型。
名词次序:间接宾语在直接宾语之前,所以找到两个名词,次序在前面的那个名词,是间接宾语,次序在后面的那个名词是直接宾语。
宾语补足语句型:
和主谓宾句型不同,宾语补足语句型含有主谓宾句型的部分,但宾语后面还有个动作(动词),也就是宾语补足语。
因此看宾语后面是否还有动词,是判断宾语补足语句型的方法。
但是有两个动词就麻烦了,如何判断这个动词是谓语动词还是宾语补足语动词呢?那就需要先把所有动词找出来,如果是宾语补足语动词,那么这个动词在谓语动词的后面,如果是谓语动词,则在前面。
既然要存放多个动词进行判断,就要有动词槽(VerbBox)。
动词次序:谓语动词在宾语补足语动词之前,所以找到两个动词,词语次序在前面的是谓语动词,词语次序在后面的是宾语补足语动词。
宾语补足语动词后面还有个名词,宾语补足语动词和这个名词合并在一起,作为宾语补足语。例如他让我打扫教室。如果宾语补足语只是“打扫”,话就说不清楚了。但是有些宾语补足语,就只有动词,后面没有名词,例如“他让我跳舞”就只有“跳舞”这一个动词,“跳舞”这个词后面没有名词,因为“跳舞”是不及物动词。
双宾语句型和宾语补足语句型,都是由主谓宾句型拓展而成的。双宾语句型在主谓宾句型的基础上,多加了一个宾语。宾语补足语句型在主谓宾句型的基础上,多加了一个动词(宾语补足语)。所以先完成主谓宾句型,再根据是否有拓展,来判断是不是双宾语句型或宾语补足语句型。
在主谓宾句型的基础上,如果没有宾语,就是主谓句型。如果没有主语,就是省略主语,例如对一个人喊“过来”,这句话的全句显然是“你过来”。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Mono.Data.Sqlite;
public class sqlitecon : MonoBehaviour
{
public TMP_Text tmpText;//输出框对象
string ShowText;//输出框的内容
string[] noun = new string[7128];//名词数组,名词数量7128
string[] verb = new string[5886];//动词数组,动词数量5886
int i = 0;//数组用的循环变量
public TMP_InputField inputField;//输入框对象
string shuru = "";//输入框的内容
string FindSubject = "";//找到的主语
string FindVerb = "";//找到的谓语动词
string FindObject = "";//找到的宾语
string FindBuVerb = "";//宾语补足语的动词
string FindBuNoun = "";//宾语补足语的名词
string FindJianObject = "";//找到的间接宾语
string FindZhiObject = "";//找到的直接宾语
string NounBox1 = "";//名词槽1
string NounBox2 = "";//名词槽2
string NounBox3 = "";//名词槽3
string NounBox4 = "";//名词槽4
string VerbBox1 = "";//动词槽1
string VerbBox2 = "";//动词槽2
string VerbBox3 = "";//动词槽3
string VerbBox4 = "";//动词槽4
string SentenceType = "";//句型
// Start is called before the first frame update
void Start()
{
inputField.onEndEdit.AddListener(OnInputEndEdit);//输入完成后,对回车键的响应
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
string sqlQuery = "SELECT word_col FROM noun";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充名词数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
while (dbReader.Read())
{
noun[i] = dbReader.GetValue(0).ToString();//GetValue(0)表示结果集的第一列,因为只查询了一列,所以返回的结果集就一列
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示名词数量
//填充动词数组
//第一步:sql指令
sqlQuery = "SELECT word_col FROM verb";//sql指令
//第二步:执行指令
//dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充动词数组
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
verb[i] = dbReader.GetValue(0).ToString();
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示动词数量
dbConnection.Close();
}
// Update is called once per frame
void Update()
{
}
void OnInputEndEdit(string value)
{
shuru = inputField.text;//输入框的值
//找谓语动词
string jieguo = "不包含";//默认值是不包含动词
int m = verb.Length;//动词数组的长度,也就是有多少个动词
VerbBox1 = "";
VerbBox2 = "";
VerbBox3 = "";
VerbBox4 = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和动词的包含关系
就是用句子和动词数组的动词,一一比对,来判断是否包含动词
n的值从0逐渐增长到动词数组的动词数量值,这样数组也就经历了所有动词
*/
if (shuru.Contains(verb[n]))//包含动词
{
if (VerbJudge(shuru,verb[n]) == true)//是动词,不是名词
{
jieguo = "包含";
FindVerb = verb[n];//找到了动词
VerbCover(shuru,verb[n]);//把动词放入动词槽里,看看有几个动词
}
}
}
if(jieguo == "包含")//包含动词
{
SentenceType = SentenceJudge();//判断句型(仅从动词情况来判断句型,还不是完全清楚的判断,之后还需进一步判断)
UnityEngine.Debug.Log("句型:" + SentenceType);
SplitSentence();
}
//tmpText.text = jieguo;//显示结果
}
void SplitSentence()
{
/*
对于主谓宾句型,先找出动词,然后以动词为分割符号,分割句子。动词左边分割出的句子的名词就是主语,动词右边分割出的句子的名词就是宾语
先举个例子简单说明一下字符串分割的基本原理:
string str = "白色的猫嘲笑黑色的鼠";//全句
string word = "嘲笑";//指定词
string res = "";//结果
int chang = 0;//全句长度
int index = 0;//指定词语的起始位置
int LastIndex = 0;//指定词语最后一个字符在全句中的位置
int jie = 0;//临时变量
//计算全句长度
chang = str.Length;//显示字符个数,从1开始计算
//计算指定字符在全句中的位置
index = str.IndexOf(word) + 1;//默认从0计算,例如第2个字符,显示为1,而不是2。为了调整为1开始计算,所以加1
//计算指定词语最后一个字符在全句中的位置
LastIndex = str.IndexOf(word) + word.Length;
//截取第3个字符右边的1个字符
Substring(开始位置, 向右截取长度),从1开始计算,不是0
res = str.Substring(3,1); //从第3个字符开始,向右截取1个字符
//截取指定字符右边的全部字符
jie = chang - LastIndex;//截取长度 = 全句长度 - 指定词语最后一个字符的位置长度
res = str.Substring(LastIndex, jie);
res = str.Substring(str.IndexOf(word) + word.Length, str.Length - (str.IndexOf(word) + word.Length));//展开形式
//截取指定字符左边的全部字符
res = str.Substring(0, index);//从句子开始的0位置,截取长度是指定字符的位置长度
res = str.Substring(0, str.IndexOf(word));//变化形式
//截取两个指定字符之间的全部字符
string word1 = "的猫";
string word2 = "的鼠";
int Word1LastIndex = str.IndexOf(word1) + word1.Length;
int Word2StartIndex = str.IndexOf(word2);
res = str.Substring(Word1LastIndex, Word2StartIndex - Word1LastIndex);
res = str.Substring(str.IndexOf(word1) + word1.Length, str.IndexOf(word2) - (str.IndexOf(word1) + word1.Length));//展开形式
//数组形式截取字符
//前面定义了:str = "白色的猫吃黑色的鼠"; word = "吃";
string[] shuzu = str.Split(word);//按指定分割符分割字符串,并存入数组中
UnityEngine.Debug.Log(shuzu[0]);//显示:白色的猫
UnityEngine.Debug.Log(shuzu[1]);//显示:黑色的鼠
//或逐一显示数组全部
foreach (string part in shuzu)
{
UnityEngine.Debug.Log(part);
}
*/
string LeftPart = "";//谓语动词的左边句
string RightPart = "";//谓语动词的右边句
//也可能找到一个动词(主谓宾句型),也可能找到两个动词(宾语补足语句型)
if (VerbBox1 != "" && VerbBox2 == "")//只找到1个动词,那就是谓语动词
{
FindVerb = VerbBox1;
}
else if (VerbBox1 != "" && VerbBox2 != "")//找到2个动词
{
FindVerb = VerbBox1;//位次在前面的动词是谓语动词
FindBuVerb = VerbBox2;//位次在后面的动词是宾语补足语动词
}
LeftPart = shuru.Substring(0, shuru.IndexOf(FindVerb));
RightPart = shuru.Substring(shuru.IndexOf(FindVerb) + FindVerb.Length, shuru.Length - (shuru.IndexOf(FindVerb) + FindVerb.Length));
/*
例如句子(shuru)是白色的猫吃黑色的鼠
find_word:吃
LeftPart:白色的猫
RightPart:黑色的鼠
UnityEngine.Debug.Log(find_verb);
UnityEngine.Debug.Log(LeftPart);
UnityEngine.Debug.Log(RightPart);
*/
if (LeftPart != "")
{
FindSubject = SearchNoun(LeftPart);//在谓语动词左边句找名词(主语)
}
if (SentenceType == "双宾语")//双宾语句型
{
FindObject = SearchNoun(RightPart);//找名词
//谓语动词右边句里,没有第二个宾语名词,那就不是双宾语
//例如虽然有双宾语句的标志动词“教”字,但他教我数学,是双宾语句,而他教书,是主谓宾句型
if (NounBox2 == "")
{
SentenceType = "主谓宾";
}
else
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("间接宾语:" + FindJianObject);
UnityEngine.Debug.Log("直接宾语:" + FindZhiObject);
}
}
if (SentenceType == "主谓宾")//主谓宾句型
{
if (RightPart != "")
{
FindObject = SearchNoun(RightPart);//在谓语动词右边句找名词(宾语)
}
//显示结果
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("宾语:" + FindObject);
}
if (SentenceType == "宾语补足语")//宾语补足语句型
{
//谓语动词到宾语补足语动词之间的部分里的名词,是宾语名词
string temp = "";
//截取谓语动词FindVerb和宾语补足语动词FindBuVerb之间的部分
temp = shuru.Substring(shuru.IndexOf(FindVerb) + FindVerb.Length, shuru.IndexOf(FindBuVerb) - (shuru.IndexOf(FindVerb) + FindVerb.Length));
FindObject = SearchNoun(temp);//找名词
//宾语补足语右边句的名词,是宾语补足语名词,而不是宾语名词
int WordLastChar = shuru.IndexOf(FindBuVerb) + FindBuVerb.Length;//宾语补足语动词最后一个字符的位置
if (WordLastChar < shuru.Length)//宾语补足语动词最后一个字符的位置没有到全句末尾,就是说宾语补足语动词后面还有内容,那就是宾语补足语名词
{
//截取宾语补足语动词右边的内容
FindBuNoun = shuru.Substring(shuru.IndexOf(FindBuVerb) + FindBuVerb.Length, shuru.Length - (shuru.IndexOf(FindBuVerb) + FindBuVerb.Length));
}
//显示结果
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("宾语:" + FindObject);
UnityEngine.Debug.Log("宾语补足语动词:" + FindBuVerb);
UnityEngine.Debug.Log("宾语补足语名词:" + FindBuNoun);
}
/*
靠句子包含的词直接与词库的词对比,来找主语(名词)、谓语(动词)、宾语(名词),会有问题:
第一个问题:熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
所以创建一个函数:WordCover(覆盖)。
词语槽(NounBox)存放这些找到词,以实现覆盖和吸收。
第二个问题:熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
对于第二个问题的解决方法:
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
所以创建一个de函数。
第三个问题:“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 学 | r1 | 生 |
+----------+---------+--------------+
| 压 | l1 | 气 |
+----------+---------+--------------+
word_col:判断这个字是动词还是名词。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
所以创建一个VerbJudge函数。
*/
}
string SearchNoun(string PartSentence)
{
//找名词
string jieguo = "不包含";//默认值是不包含
string FindNoun = "";//要找的名词
int m = noun.Length;//名词数组的长度,也就是有多少个名词
//for循环前,先把词语槽清空,因为for循环时,调用的函数WordCover要用词语槽,来完成词语的覆盖和吸收
NounBox1 = "";
NounBox2 = "";
NounBox3 = "";
NounBox4 = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和名词的包含关系
就是用句子和名词数组的名词,一一比对,来判断是否包含名词
n的值从0逐渐增长到名词数组的名词数量值,这样数组也就经历了所有名词
*/
if (PartSentence.Contains(noun[n]))//包含
{
jieguo = "包含";
if (de(PartSentence, noun[n]) == false)//找到的名词右边的第一个字符不是“的”字,才算是名词,否则是名词所有格
{
NounCover(noun[n]);
FindNoun = NounBox1;
}
}
}
if (jieguo == "包含")
{
return FindNoun;
}
else
{
return "";
}
}
void NounCover(string FindWord)
{
/*
熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
词语槽(NounBox)存放这些找到词,以实现覆盖和吸收。
做了4个词语槽(NounBox),为了以后适应复杂的句子,但简单的主谓宾句型,一个词语槽就够了。
*/
if (NounBox1 == "" && FindWord != "")//词语槽还是空的,说明这是找到的第一个词
{
NounBox1 = FindWord;//找到的第1个词,放入词语槽
FindWord = "";//置空,免得填到词语槽2了
}
else if (NounBox1 != "" && FindWord != "")//词语槽1已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox1))//覆盖:例如找到的词(FindWord)是熊猫,词语槽1(NounBox1)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox1 = FindWord;//词语槽1的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽2了
}
else if (NounBox1.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽1(NounBox1)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,不要这个词了,免得填到词语槽2了
}
}
if (NounBox2 == "" && FindWord != "")//词语槽2是空的,FindWord经过词语槽1,没有覆盖或吸收,说明FindWord和词语槽1的词无关,例如FindWord是竹子
{
NounBox2 = FindWord;//找到的第2个词,放入词语槽
FindWord = "";//置空,免得填到词语槽3了
}
else if (NounBox2 != "" && FindWord != "")//词语槽2已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox2))//覆盖:例如找到的词(FindWord)是熊猫,词语槽2(NounBox2)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox2 = FindWord;//词语槽2的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽3了
}
else if (NounBox2.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽2(NounBox2)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽3了
}
}
if (NounBox3 == "" && FindWord != "")//词语槽3是空的,FindWord经过词语槽2,没有覆盖或吸收,说明FindWord和词语槽2的词无关,例如FindWord是竹子
{
NounBox3 = FindWord;//找到的第3个词,放入词语槽
FindWord = "";//置空,免得填到词语槽4了
}
else if (NounBox3 != "" && FindWord != "")//词语槽3已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox3))//覆盖:例如找到的词(FindWord)是熊猫,词语槽3(NounBox3)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox3 = FindWord;//词语槽3的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽4了
}
else if (NounBox3.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽3(NounBox3)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽4了
}
}
if (NounBox4 == "" && FindWord != "")//词语槽4是空的,FindWord经过词语槽3,没有覆盖或吸收,说明FindWord和词语槽3的词无关,例如FindWord是竹子
{
NounBox4 = FindWord;//找到的第4个词,放入词语槽
FindWord = "";//置空
}
else if (NounBox4 != "" && FindWord != "")//词语槽4已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox4))//覆盖:例如找到的词(FindWord)是熊猫,词语槽4(NounBox4)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox4 = FindWord;//词语槽4的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空
}
else if (NounBox4.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽4(NounBox4)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空
}
}
//排序
if (NounBox1 != "" && NounBox2 != "")//招到了2个名词,放在NounBox1和NounBox2
{
string temp = "";//临时变量
if (shuru.IndexOf(NounBox1) > shuru.IndexOf(NounBox2))//如果NounBox1的名词在句子中的位置大于NounBox2的名词在句子中的位置
{
//交换位置,在句子中位置小的名词放前面,从而确保双宾语句型时,NounBox1放的是间接宾语,NounBox2放的是直接宾语,毕竟间接宾语在直接宾语前面
temp = NounBox1;
NounBox1 = NounBox2;
NounBox2 = temp;
}
FindJianObject = NounBox1;
FindZhiObject = NounBox2;
}
}
void VerbCover(string str,string FindWord)
{
if (VerbBox1 == "" && FindWord != "")//动词槽还是空的,说明这是找到的第一个词
{
VerbBox1 = FindWord;//找到的第1个词,放入动词槽
FindWord = "";//置空,免得填到动词槽2了
}
else if (VerbBox1 != "" && FindWord != "")//动词槽1已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox1))//覆盖:例如找到的词(FindWord)是敲打,动词槽1(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox1 = FindWord;//词语槽1的词:长词覆盖短词,例如“敲打”覆盖“打”
FindWord = "";//置空,免得填到动词槽2了
}
else if (VerbBox1.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽1(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,不要这个词了,免得填到动词槽2了
}
}
if (VerbBox2 == "" && FindWord != "")//动词槽2是空的,FindWord经过动词槽1,没有覆盖或吸收,说明FindWord和动词槽1的词无关,例如FindWord是喜欢
{
VerbBox2 = FindWord;//找到的第2个词,放入动词槽
FindWord = "";//置空,免得填到动词槽3了
}
else if (VerbBox2 != "" && FindWord != "")//动词槽2已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox2))//覆盖:例如找到的词(FindWord)是敲打,动词槽2(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox2 = FindWord;//词语槽2的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽3了
}
else if (VerbBox2.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽2(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,免得填到词语槽3了
}
}
if (VerbBox3 == "" && FindWord != "")//动词槽3是空的,FindWord经过动词槽1和2,没有覆盖或吸收,说明FindWord和动词槽1、2的词无关,例如FindWord是喜欢
{
VerbBox3 = FindWord;//找到的第3个词,放入词语槽
FindWord = "";//置空,免得填到词语槽4了
}
else if (VerbBox3 != "" && FindWord != "")//动词槽3已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox3))//覆盖:例如找到的词(FindWord)是敲打,动词槽3(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox3 = FindWord;//词语槽3的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽4了
}
else if (VerbBox3.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽3(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,免得填到词语槽4了
}
}
if (VerbBox4 == "" && FindWord != "")//动词槽4是空的,FindWord经过动词槽1、2、3,没有覆盖或吸收,说明FindWord和动词槽1、2、3的词无关,例如FindWord是喜欢
{
VerbBox4 = FindWord;//找到的第4个词,放入词语槽
FindWord = "";//置空
}
else if (VerbBox4 != "" && FindWord != "")//动词槽4已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox4))//覆盖:例如找到的词(FindWord)是敲打,动词槽4(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox4 = FindWord;//词语槽4的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空
}
else if (VerbBox4.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽4(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空
}
}
//排序
if (VerbBox1 != "" && VerbBox2 != "")//招到了个动词,放在VerbBox1和VerbBox2
{
string temp;//临时变量
if (shuru.IndexOf(VerbBox1) > shuru.IndexOf(VerbBox2))//如果VerbBox1的动词在句子中的位置大于VerbBox2的动词在句子中的位置
{
//交换位置,在句子中位置小动词的放前面,从而确保VerbBox1放的是谓语动词,而宾语补足语动词放到VerbBox2
temp = VerbBox1;
VerbBox1 = VerbBox2;
VerbBox2 = temp;
}
}
}
bool de(string str,string word)
{
/*
熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
UnityEngine.Debug.Log(res);//显示:的
以上内容是解释原理,下面是运行程序:
*/
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLastChar = str.IndexOf(word) + word.Length;
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
if (res == "的")
{
return true;
}
else
{
return false;
}
}
bool VerbJudge(string str,string word)
{
/*
“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 学 | r1 | 生 |
+----------+---------+--------------+
| 压 | l1 | 气 |
+----------+---------+--------------+
word_col:判断这个字是动词还是名词,也就是辨析字。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。
“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
不容易理解的一处:
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 吹 | l1 | 电 |
+----------+---------+--------------+
“吹”字本身做动词,但在“电吹风”这个词里做名词,但我不用把“电吹风”这个三个字都判断,我只要判断“电吹”两个字就可以了。
遇到单字动词的时候,先看这个字是否在词性辨析表里,
如果在,type_col要求是r1(right1,就是要辨析的字的右边1个字符),那就看句子中要辨析的字的右边1个字符是不是符合词性表中的字,
如果符合,要辨析的字就是名词,而不是动词了。
例如学生看书,这句话先找到了动词“学”,在词性辨析表里,“学”字的type_col是r1,content_col是“生”字,
那就在句子中,看“学”字右边的1个字符是不是“生”字,如果是,“学”字就不做动词,而做名词了。
一个要辨析的字,type_col有四种可能:r1、r2、l1、l2,也就是右边1个字,右边2个字,左边1个字,左边2个字,那就要会四个方法:
符合r1:找辨析字右边1个字符:res = str.Substring(str.IndexOf(word) + word.Length, 1);
符合r2:找辨析字右边2个字符:res = str.Substring(str.IndexOf(word) + word.Length, 2);
符合l1:找辨析字左边1个字符:res = str.Substring(str.IndexOf(word) - 1, 1);
符合l2:找辨析字左边2个字符:res = str.Substring(str.IndexOf(word) - 2, 1);
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
res = str.Substring(str.IndexOf(word) + word.Length, 1);//变化形式
}
UnityEngine.Debug.Log(res);//显示:的
//指定词语左边1个字符
res = str.Substring(index - 1, 1);
res = str.Substring(str.IndexOf(word) - 1, 1);//变化形式
UnityEngine.Debug.Log(res);//显示:吃
以上内容是解释原理,下面是运行程序:
*/
string[] TypeCol = new string[100];//把词性辨析表的辨析字对应的type_col值填充此数组
string[] ContentCol = new string[100];//把词性辨析表的辨析字对应的content_col值填充此数组
string res = "";//截取的字符
bool shima = true;//默认判断是动词
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
//字符型变量要有引号,数字型变量不需要引号
//word是变量,动态的,不能直接放到sql语句里面
string sqlQuery = "select type_col,content_col from verb_judge where word_col = '" + word + "'";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充词性辨析数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
//查询了2列(type_col和content_col),所以返回的结果集有2列,分别用GetValue(0)和GetValue(1)
TypeCol[i] = dbReader.GetValue(0).ToString();//返回的结果集的第1列
ContentCol[i] = dbReader.GetValue(1).ToString();//返回的结果集的第2列
i++;//虽然定义数组长度为10,但i不一定填满了10
}
dbReader.Close();
dbConnection.Close();
if (i > 0)//在词性辨析表里找到内容了,否则i还是默认的0
{
for (int n = 0; n < i; n++)//遍历词性辨析表找到的各种结果
{
if (TypeCol[n] == "r1")//right1:右边1个字符
{
if (str.IndexOf(word) + word.Length + 1 <= str.Length)//要往右判断1个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 1);//截取动词右边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "r2")//right2:右边2个字符
{
if (str.IndexOf(word) + word.Length + 2 <= str.Length)//要往右判断2个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 2);//截取动词右边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l1")//left1:左边1个字符
{
if (str.IndexOf(word) - 1 >= 0)//要往左判断1个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 1, 1);//截取动词左边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l2")//left2:左边2个字符
{
if (str.IndexOf(word) - 2 >= 0)//要往左判断2个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 2, 2);//截取动词左边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
}
}
i = 0;
return shima;
}
string SentenceJudge()
{
/*
判断句型:
基本单句有六种句型:
只有性质状态(表语):真漂亮、对啊、太好了。句子里没有谓语动词,其余五种句型里,都有谓语动词。
主语(动作执行者)-谓语(动作):张三摔倒。
主语(动作执行者)-谓语(动作)-宾语(动作对象):猫吃鼠。
主语-谓语(是)-表语(表明主语的身份和性质状态):张三是老师,太阳是美丽的。
双宾语句型:主语(传输的人)-谓语(传输动作)-间接宾语(传输对象)-直接宾语(传输的事物):张三给李四苹果,张三教李四数学。
宾语补足语句型:主语-谓语(例如把、使、让)-宾语-宾语补足语(做什么):张三让李四跳舞,张三把房间弄脏了。
前面只说了主谓宾句型,还要处理其它句型。
双宾语句型:
双宾语句型的谓语动词后面有两个名词,例如张三给李四苹果,李四是间接宾语(名词),苹果是直接宾语(名词)。
但是有两个名词的就是双宾语句型吗?不是的。例如张三喜欢足球学校。谓语动词后面有两个名词:足球、学校,但显然足球学校是一个整体名词,也就是主谓宾句型,而不是双宾语句型。因此判断双宾语句型,还要看谓语动词是不是适合双宾语句型的。
双宾语句型的谓语动词主要是传输事物的动词:给、送给、教。
那么谓语动词是双宾语句型的动词(例如给、教),且谓语动词后面有两个名词(体现为谓语动词右边的语句处理时,名词槽NounBox有两个名词,NounBox1和NounBox2都有值),就可以判断为双宾语句型。
还有,像“足球学校”这样两个名词连在一起,就要合并成一个名词,作为主语或宾语。
仅从双宾语句型的标志动词“教”判断双宾语句型,不一定准确,例如“他教我数学”是双宾语句型,但“他教书”就不是双宾语句型,所以还要根据宾语名词的数量,来判断到底是不是双宾语句型,如果动词右边只有一个名词,例如“他教书”的“书”,句子就不是双宾语句型。所以通过谓语动词判断一个句子是双宾语句型后,根据找到的名词数量,例如只有一个宾语名词,那么就要把双宾语句型,修正回主谓宾句型。
名词次序:间接宾语在直接宾语之前,所以找到两个名词,次序在前面的那个名词,是间接宾语,次序在后面的那个名词是直接宾语。
宾语补足语句型:
和主谓宾句型不同,宾语补足语句型含有主谓宾句型的部分,但宾语后面还有个动作(动词),也就是宾语补足语。
因此看宾语后面是否还有动词,是判断宾语补足语句型的方法。
但是有两个动词就麻烦了,如何判断这个动词是谓语动词还是宾语补足语动词呢?那就需要先把所有动词找出来,如果是宾语补足语动词,那么这个动词在谓语动词的后面,如果是谓语动词,则在前面。
既然要存放多个动词进行判断,就要有动词槽(VerbBox)。
动词次序:谓语动词在宾语补足语动词之前,所以找到两个动词,词语次序在前面的是谓语动词,词语次序在后面的是宾语补足语动词。
宾语补足语动词后面还有个名词,宾语补足语动词和这个名词合并在一起,作为宾语补足语。例如他让我打扫教室。如果宾语补足语只是“打扫”,话就说不清楚了。但是有些宾语补足语,就只有动词,后面没有名词,例如“他让我跳舞”就只有“跳舞”这一个动词,“跳舞”这个词后面没有名词,因为“跳舞”是不及物动词。
双宾语句型和宾语补足语句型,都是由主谓宾句型拓展而成的。双宾语句型在主谓宾句型的基础上,多加了一个宾语。宾语补足语句型在主谓宾句型的基础上,多加了一个动词(宾语补足语)。所以先完成主谓宾句型,再根据是否有拓展,来判断是不是双宾语句型或宾语补足语句型。
在主谓宾句型的基础上,如果没有宾语,就是主谓句型。如果没有主语,就是省略主语,例如对一个人喊“过来”,这句话的全句显然是“你过来”。
*/
if (VerbBox1 == "")//没有动词
{
return "只有性质状态";//只有性质状态的句型
}
else if (VerbBox1 != "" && VerbBox2 == "")//有1个动词
{
if (VerbBox1 == "给" || VerbBox1 == "送" || VerbBox1 == "送给" || VerbBox1 == "教")//双宾语句型的常见动词(标志词)
{
return "双宾语";//双宾语句型
}
else
{
return "主谓宾";//主谓宾句型
}
}
else if (VerbBox1 != "" && VerbBox2 != "")//有2个动词
{
return "宾语补足语";//宾语补足语句型
}
else
{
return "其它";
}
}
}
第三章
省略主语有两种情况:一种是主动语态省略主语,例如“跳过去”,全句指“你跳过去”。另一种是被动语态省略主语,例如“张三被打了”,没说谁打了张三,这里张三是宾语。如果说“李四打了张三”,李四就是主语。
被动语态的标志是“被”字,如果没有“被”字,而且省略了主语,就是主动语态省略主语的情况,那么这种情况下,主语应该填什么呢?例如“过来”,一般指“你过来”,但“走吧”一般指“我们走吧”。所以程序要根据具体的动词来判断省略的主语应该填什么。但是动词太多,每个动词都要设置省略的主语判断,太麻烦。所以省略主语,按最通常情况,就默认填“你”字,作为主语。如果主语是“我们”而不是“你”字,就不该省略主语。
被动语态应该还原为主动语态去理解,但被动语态往往没有主语,那么默认主语应该填什么呢?毕竟不知道主语,那就填“事物”这个词作为主语。
程序分析句子时,被动语态的主语位置的词,是宾语。例如“李四被打了”,李四在谓语动词左边句,程序会把李四当成主语,但在被动语态句里,李四不是主语,所以有“被”字的时候,主语要挪动到宾语位置,然后在主语位置补充“事物”这个词,作为主语。
但是有些时候,被动语态的主语是说明了的,例如“李四被张三打了”就还原为主动语态“张三打了李四”,张三做主语,而不是填“事物”做主语。
简而言之,被动语态里,主语放到了宾语位置,宾语放到了主语位置,所以变为主动语态时,要把宾语挪回主语位置,主语挪回宾语位置。
如果被动语态有主语,例如“李四被张三打了”,那么主语(张三)位于“被”字与谓语动词之间。
那么谓语动词左边句中,又分为“被”字左边句和“被”字右边句,被字左边句里的名词是宾语,被字右边句里的名词是主语。
名词合并:
名词合并:例如“足球学校”这个词,会被当成两个名词“足球”和“学校”。但实际中,要把它们合并成一个组合名词,作为主语或宾语。
合并方法:如果两个字符(词语)是连续的,那么这两个词语之间的内容为空。
动词合并:
例如“应该爱”是两个动词:情态动词“应该”和普通动词“爱”,应该合并成一个动词。
动词前面是否有否定词,也很重要。
例如“他爱猫”和“他不爱猫”,虽然谓语动词都是“爱”字,但前面加个“不”字,意义就相反了。所以看谓语动词前面是否有否定词,是很重要的事。
谓语动词前面的否定词,一般有不、不要、不可以、不应该、不能、别。
还有不确定肯定还是否定动词,例如“他不一定去”,“去”字是动词,但是动词前的“不一定”,并不像是“不”字那样对动词进行否定,而是对动词既不像是肯定,也不像是否定,而是不确定。
因此对每句话的谓语动词,都要加一个性质:肯定、否定、不确定。
但不确定,有时候偏向于肯定,例如“他可能去”。有时候不确定偏向于否定,例如“他不太可能去”以及“他或许不去”。
那么动词发生概率分为五种:肯定、偏向肯定、不确定、偏向否定、否定。
这其实就是在分析事情(谓语动词)发生的概率,这在概率分析上有用。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using Mono.Data.Sqlite;
public class sqlitecon : MonoBehaviour
{
public TMP_Text tmpText;//输出框对象
string ShowText;//输出框的内容
string[] noun = new string[7128];//名词数组,名词数量7128
string[] verb = new string[5886];//动词数组,动词数量5886
int i = 0;//数组用的循环变量
public TMP_InputField inputField;//输入框对象
string shuru = "";//输入框的内容
string FindSubject = "";//找到的主语
string FindVerb = "";//找到的谓语动词
string FindObject = "";//找到的宾语
string FindBuVerb = "";//宾语补足语的动词
string FindBuNoun = "";//宾语补足语的名词
string FindJianObject = "";//找到的间接宾语
string FindZhiObject = "";//找到的直接宾语
string SentenceType = "";//句型
string yutai = "";//语态:主动语态还是被动语态
string VerbRate = "";//动词发生概率:肯定、偏向肯定、不确定、偏向否定、否定
string NounBox1 = "";//名词槽1
string NounBox2 = "";//名词槽2
string NounBox3 = "";//名词槽3
string NounBox4 = "";//名词槽4
string VerbBox1 = "";//动词槽1
string VerbBox2 = "";//动词槽2
string VerbBox3 = "";//动词槽3
string VerbBox4 = "";//动词槽4
// Start is called before the first frame update
void Start()
{
inputField.onEndEdit.AddListener(OnInputEndEdit);//输入完成后,对回车键的响应
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
string sqlQuery = "SELECT word_col FROM noun";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充名词数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
while (dbReader.Read())
{
noun[i] = dbReader.GetValue(0).ToString();//GetValue(0)表示结果集的第一列,因为只查询了一列,所以返回的结果集就一列
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示名词数量
//填充动词数组
//第一步:sql指令
sqlQuery = "SELECT word_col FROM verb";//sql指令
//第二步:执行指令
//dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充动词数组
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
verb[i] = dbReader.GetValue(0).ToString();
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示动词数量
dbConnection.Close();
}
// Update is called once per frame
void Update()
{
}
void OnInputEndEdit(string value)
{
shuru = inputField.text;//输入框的值
//找谓语动词
string jieguo = "不包含";//默认值是不包含动词
int m = verb.Length;//动词数组的长度,也就是有多少个动词
VerbBox1 = "";
VerbBox2 = "";
VerbBox3 = "";
VerbBox4 = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和动词的包含关系
就是用句子和动词数组的动词,一一比对,来判断是否包含动词
n的值从0逐渐增长到动词数组的动词数量值,这样数组也就经历了所有动词
*/
if (shuru.Contains(verb[n]))//包含动词
{
if (VerbJudge(shuru,verb[n]) == true)//是动词,不是名词
{
jieguo = "包含";
FindVerb = verb[n];//找到了动词
VerbCover(shuru,verb[n]);//把动词放入动词槽里,看看有几个动词
VerbOrder();//动词排序
VerbJoin();//动词结合
}
}
}
if(jieguo == "包含")//包含动词
{
VerbRateJudge();//动词发生概率:肯定、偏向肯定、不确定、偏向否定、否定
SentenceType = SentenceJudge();//判断句型(仅从动词情况来判断句型,还不是完全清楚的判断,之后还需进一步判断)
SplitSentence();
}
}
void SplitSentence()
{
/*
对于主谓宾句型,先找出动词,然后以动词为分割符号,分割句子。动词左边分割出的句子的名词就是主语,动词右边分割出的句子的名词就是宾语
先举个例子简单说明一下字符串分割的基本原理:
string str = "白色的猫嘲笑黑色的鼠";//全句
string word = "嘲笑";//指定词
string res = "";//结果
int chang = 0;//全句长度
int index = 0;//指定词语的起始位置
int LastIndex = 0;//指定词语最后一个字符在全句中的位置
int jie = 0;//临时变量
//计算全句长度
chang = str.Length;//显示字符个数,从1开始计算
//计算指定字符在全句中的位置
index = str.IndexOf(word) + 1;//默认从0计算,例如第2个字符,显示为1,而不是2。为了调整为1开始计算,所以加1
//计算指定词语最后一个字符在全句中的位置
LastIndex = str.IndexOf(word) + word.Length;
//截取第3个字符右边的1个字符
Substring(开始位置, 向右截取长度),从1开始计算,不是0
res = str.Substring(3,1); //从第3个字符开始,向右截取1个字符
//截取指定字符右边的全部字符
jie = chang - LastIndex;//截取长度 = 全句长度 - 指定词语最后一个字符的位置长度
res = str.Substring(LastIndex, jie);
res = str.Substring(str.IndexOf(word) + word.Length, str.Length - (str.IndexOf(word) + word.Length));//展开形式
//截取指定字符左边的全部字符
res = str.Substring(0, index);//从句子开始的0位置,截取长度是指定字符的位置长度
res = str.Substring(0, str.IndexOf(word));//变化形式
//截取两个指定字符之间的全部字符
string word1 = "的猫";
string word2 = "的鼠";
int Word1LastIndex = str.IndexOf(word1) + word1.Length;
int Word2StartIndex = str.IndexOf(word2);
res = str.Substring(Word1LastIndex, Word2StartIndex - Word1LastIndex);
res = str.Substring(str.IndexOf(word1) + word1.Length, str.IndexOf(word2) - (str.IndexOf(word1) + word1.Length));//展开形式
//数组形式截取字符
//前面定义了:str = "白色的猫吃黑色的鼠"; word = "吃";
string[] shuzu = str.Split(word);//按指定分割符分割字符串,并存入数组中
UnityEngine.Debug.Log(shuzu[0]);//显示:白色的猫
UnityEngine.Debug.Log(shuzu[1]);//显示:黑色的鼠
//或逐一显示数组全部
foreach (string part in shuzu)
{
UnityEngine.Debug.Log(part);
}
以上注释掉的内容,只是解释原理,下面是运行的程序:
*/
string LeftPart = "";//谓语动词的左边句
string RightPart = "";//谓语动词的右边句
//也可能找到一个动词(主谓宾句型),也可能找到两个动词(宾语补足语句型)
if (VerbBox1 != "" && VerbBox2 == "")//只找到1个动词,那就是谓语动词
{
FindVerb = VerbBox1;
}
else if (VerbBox1 != "" && VerbBox2 != "")//找到2个动词
{
FindVerb = VerbBox1;//位次在前面的动词是谓语动词
FindBuVerb = VerbBox2;//位次在后面的动词是宾语补足语动词
}
LeftPart = shuru.Substring(0, shuru.IndexOf(FindVerb));
RightPart = shuru.Substring(shuru.IndexOf(FindVerb) + FindVerb.Length, shuru.Length - (shuru.IndexOf(FindVerb) + FindVerb.Length));
/*
例如句子(shuru)是白色的猫吃黑色的鼠
find_word:吃
LeftPart:白色的猫
RightPart:黑色的鼠
UnityEngine.Debug.Log(find_verb);
UnityEngine.Debug.Log(LeftPart);
UnityEngine.Debug.Log(RightPart);
*/
/*
省略主语有两种情况:一种是主动语态省略主语,例如“跳过去”,全句指“你跳过去”。另一种是被动语态省略主语,例如“张三被打了”,没说谁打了张三,这里张三是宾语。如果说“李四打了张三”,李四就是主语。
被动语态的标志是“被”字,如果没有“被”字,而且省略了主语,就是主动语态省略主语的情况,那么这种情况下,主语应该填什么呢?例如“过来”,一般指“你过来”,但“走吧”一般指“我们走吧”。所以程序要根据具体的动词来判断省略的主语应该填什么。但是动词太多,每个动词都要设置省略的主语判断,太麻烦。所以省略主语,按最通常情况,就默认填“你”字,作为主语。如果主语是“我们”而不是“你”字,就不该省略主语。
被动语态应该还原为主动语态去理解,但被动语态往往没有主语,那么默认主语应该填什么呢?毕竟不知道主语,那就填“事物”这个词作为主语。
程序分析句子时,被动语态的主语位置的词,是宾语。例如“李四被打了”,李四在谓语动词左边句,程序会把李四当成主语,但在被动语态句里,李四不是主语,所以有“被”字的时候,主语要挪动到宾语位置,然后在主语位置补充“事物”这个词,作为主语。
但是有些时候,被动语态的主语是说明了的,例如“李四被张三打了”就还原为主动语态“张三打了李四”,张三做主语,而不是填“事物”做主语。
简而言之,被动语态里,主语放到了宾语位置,宾语放到了主语位置,所以变为主动语态时,要把宾语挪回主语位置,主语挪回宾语位置。
如果被动语态有主语,例如“李四被张三打了”,那么主语(张三)位于“被”字与谓语动词之间。
那么谓语动词左边句中,又分为“被”字左边句和“被”字右边句,被字左边句里的名词是宾语,被字右边句里的名词是主语。
*/
yutai = "主动";//默认主动语态
if (SentenceType == "主谓宾" && shuru.Contains("被"))//语句中包含“被”字
{
if (shuru.Contains("被子") == false && shuru.Contains("被褥") == false)//语句中包含“被”字,但不是“被子”这个名词,才能指被动语态的“被”字
{
yutai = "被动";//被动语态
}
else
{
yutai = "主动";//主动语态
}
}
else//语句中没有包含“被”字
{
yutai = "主动";//主动语态
}
if (LeftPart != "")//谓语动词左边句有内容
{
if (yutai == "主动")//主动语态
{
FindSubject = SearchNoun(LeftPart);//在谓语动词左边句找名词(主语)
}
else if (yutai == "被动")//被动语态
{
string bei = "被";
string BeiLeft = "";
string BeiRight = "";
//被字左边句
BeiLeft = LeftPart.Substring(0, LeftPart.IndexOf(bei));
FindObject = SearchNoun(BeiLeft);//被字左边句的名词是宾语
//被字右边句
BeiRight = LeftPart.Substring(LeftPart.IndexOf(bei) + bei.Length, LeftPart.Length - (LeftPart.IndexOf(bei) + bei.Length));
FindSubject = SearchNoun(BeiRight);//被字右边句的名词是主语
//如果没有主语,就填补“事物”这个词作为主语,毕竟被动语态经常没有主语
if (FindSubject == "" || FindSubject == null)//主语为空或主语不存在
{
FindSubject = "事物";
}
}
}
//如果省略主语,则填补省略的主语
if (yutai == "主动")
{
if (FindSubject == "" || FindSubject == null)//主语为空或主语不存在
{
FindSubject = "你";//默认填补“你”字做主语
}
}
if (SentenceType == "双宾语")//双宾语句型
{
FindObject = SearchNoun(RightPart);//找名词
//谓语动词右边句里,没有第二个宾语名词,那就不是双宾语
//例如虽然有双宾语句的标志动词“教”字,但他教我数学,是双宾语句,而他教书,是主谓宾句型
if (NounBox2 == "")
{
SentenceType = "主谓宾";
}
else
{
ShowResult();//显示最终输出结果
}
}
if (SentenceType == "主谓宾")//主谓宾句型
{
if (RightPart != "")
{
if (yutai == "主动")
{
FindObject = SearchNoun(RightPart);//在谓语动词右边句找名词(宾语)
}
}
ShowResult();//显示最终输出结果
}
if (SentenceType == "宾语补足语")//宾语补足语句型
{
//谓语动词到宾语补足语动词之间的部分里的名词,是宾语名词
string temp = "";
//截取谓语动词FindVerb和宾语补足语动词FindBuVerb之间的部分
temp = shuru.Substring(shuru.IndexOf(FindVerb) + FindVerb.Length, shuru.IndexOf(FindBuVerb) - (shuru.IndexOf(FindVerb) + FindVerb.Length));
FindObject = SearchNoun(temp);//找名词
//宾语补足语右边句的名词,是宾语补足语名词,而不是宾语名词
int WordLastChar = shuru.IndexOf(FindBuVerb) + FindBuVerb.Length;//宾语补足语动词最后一个字符的位置
if (WordLastChar < shuru.Length)//宾语补足语动词最后一个字符的位置没有到全句末尾,就是说宾语补足语动词后面还有内容,那就是宾语补足语名词
{
//截取宾语补足语动词右边的内容
FindBuNoun = shuru.Substring(shuru.IndexOf(FindBuVerb) + FindBuVerb.Length, shuru.Length - (shuru.IndexOf(FindBuVerb) + FindBuVerb.Length));
}
ShowResult();//显示最终输出结果
}
/*
靠句子包含的词直接与词库的词对比,来找主语(名词)、谓语(动词)、宾语(名词),会有问题:
第一个问题:熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
所以创建一个函数:WordCover(覆盖)。
词语槽(NounBox)存放这些找到词,以实现覆盖和吸收。
第二个问题:熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
对于第二个问题的解决方法:
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
所以创建一个de函数。
第三个问题:“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 学 | r1 | 生 |
+----------+---------+--------------+
| 压 | l1 | 气 |
+----------+---------+--------------+
word_col:判断这个字是动词还是名词。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
所以创建一个VerbJudge函数。
*/
}
string SearchNoun(string PartSentence)
{
//找名词
string jieguo = "不包含";//默认值是不包含
int m = noun.Length;//名词数组的长度,也就是有多少个名词
//for循环前,先把词语槽清空,因为for循环时,调用的函数WordCover要用词语槽,来完成词语的覆盖和吸收
NounBox1 = "";
NounBox2 = "";
NounBox3 = "";
NounBox4 = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和名词的包含关系
就是用句子和名词数组的名词,一一比对,来判断是否包含名词
n的值从0逐渐增长到名词数组的名词数量值,这样数组也就经历了所有名词
*/
if (PartSentence.Contains(noun[n]))//包含
{
jieguo = "包含";
if (de(PartSentence, noun[n]) == false)//找到的名词右边的第一个字符不是“的”字,才算是名词,否则是名词所有格
{
NounCover(noun[n]);
}
}
}
if (jieguo == "包含")//找到了名词
{
NounOrder();//名词排序
//名词要先排序,才能合并名词,否则“足球”和“学校”的顺序如果变成“学校”和“足球”,那就合并成“学校足球”这个词了,而不是“足球学校”
//如果双宾语句型进行名词合并,就可能会把间接宾语名词和直接宾语名词合并到一起,成为一个名词,就不对了
if (SentenceType != "双宾语")//不是双宾语句型
{
NounJoin();//名词合并,例如把“足球”和“学校”合并成“足球学校”这一个名词
}
else if (SentenceType == "双宾语")//是双宾语句型
{
//但是如果现在处理的是双宾语结构的谓语动词左边句,也就是处理主语,还是可以名词合并的
if (shuru.IndexOf(NounBox1) < shuru.IndexOf(FindVerb))
{
NounJoin();//名词合并
}
}
return NounBox1;
}
else
{
return "";
}
}
void NounCover(string FindWord)
{
/*
熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
词语槽(NounBox)存放这些找到词,以实现覆盖和吸收。
做了4个词语槽(NounBox),为了以后适应复杂的句子,但简单的主谓宾句型,一个词语槽就够了。
*/
if (NounBox1 == "" && FindWord != "")//词语槽还是空的,说明这是找到的第一个词
{
NounBox1 = FindWord;//找到的第1个词,放入词语槽
FindWord = "";//置空,免得填到词语槽2了
}
else if (NounBox1 != "" && FindWord != "")//词语槽1已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox1))//覆盖:例如找到的词(FindWord)是熊猫,词语槽1(NounBox1)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox1 = FindWord;//词语槽1的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽2了
}
else if (NounBox1.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽1(NounBox1)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,不要这个词了,免得填到词语槽2了
}
}
if (NounBox2 == "" && FindWord != "")//词语槽2是空的,FindWord经过词语槽1,没有覆盖或吸收,说明FindWord和词语槽1的词无关,例如FindWord是竹子
{
NounBox2 = FindWord;//找到的第2个词,放入词语槽
FindWord = "";//置空,免得填到词语槽3了
}
else if (NounBox2 != "" && FindWord != "")//词语槽2已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox2))//覆盖:例如找到的词(FindWord)是熊猫,词语槽2(NounBox2)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox2 = FindWord;//词语槽2的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽3了
}
else if (NounBox2.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽2(NounBox2)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽3了
}
}
if (NounBox3 == "" && FindWord != "")//词语槽3是空的,FindWord经过词语槽2,没有覆盖或吸收,说明FindWord和词语槽2的词无关,例如FindWord是竹子
{
NounBox3 = FindWord;//找到的第3个词,放入词语槽
FindWord = "";//置空,免得填到词语槽4了
}
else if (NounBox3 != "" && FindWord != "")//词语槽3已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox3))//覆盖:例如找到的词(FindWord)是熊猫,词语槽3(NounBox3)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox3 = FindWord;//词语槽3的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽4了
}
else if (NounBox3.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽3(NounBox3)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽4了
}
}
if (NounBox4 == "" && FindWord != "")//词语槽4是空的,FindWord经过词语槽3,没有覆盖或吸收,说明FindWord和词语槽3的词无关,例如FindWord是竹子
{
NounBox4 = FindWord;//找到的第4个词,放入词语槽
FindWord = "";//置空
}
else if (NounBox4 != "" && FindWord != "")//词语槽4已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox4))//覆盖:例如找到的词(FindWord)是熊猫,词语槽4(NounBox4)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox4 = FindWord;//词语槽4的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空
}
else if (NounBox4.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽4(NounBox4)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空
}
}
/*
“足球”这个词,会找到三个名词:足、球、足球。
先找到第一个词:足,放入NounBox1。
再找到第二个词:球,放入NounBox2。
再找到第三个词:足球,会覆盖NounBox1的“足”字,但却无法覆盖NounBox2的球字。
因此程序做一些改进。
但如果幸运的:
先找到第一个词:足球,放入NounBox1。
再找到第二个词:足,被NounBox1“足球”这个词吸收,不会进入到NounBox2。
再找到第三个词:球,被NounBox1“足球”这个词吸收,也不会进入到NounBox2。
那么就不用执行下面这段程序了。
先找到那个词是不确定的,词库词语可能按笔画排序,也可能按首字母排序,就不知道先找到那个词了。
如果输入的是“皮球”这个词,而词库里没有“皮球”这个词,但有“皮”字和“球”字这两个词。
那么,NounBox1是“皮”字,NounBox2是“球”字,或NounBox1是“球”字,NounBox2是“皮”字,没有覆盖和吸收。
*/
if (NounBox1.Contains(NounBox2))//NounBox1包含了NounBox2,例如“足球”包含“球”字
{
NounBox2 = "";
if (NounBox3 != "")
{
NounBox2 = NounBox3;
NounBox3 = "";
}
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";
}
}
if (NounBox2.Contains(NounBox3))//NounBox2包含了NounBox3
{
NounBox3 = "";
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";
}
}
if (NounBox3.Contains(NounBox4))//NounBox3包含了NounBox4
{
NounBox4 = "";
}
}
void VerbCover(string str,string FindWord)
{
if (VerbBox1 == "" && FindWord != "")//动词槽还是空的,说明这是找到的第一个词
{
VerbBox1 = FindWord;//找到的第1个词,放入动词槽
FindWord = "";//置空,免得填到动词槽2了
}
else if (VerbBox1 != "" && FindWord != "")//动词槽1已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox1))//覆盖:例如找到的词(FindWord)是敲打,动词槽1(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox1 = FindWord;//词语槽1的词:长词覆盖短词,例如“敲打”覆盖“打”
FindWord = "";//置空,免得填到动词槽2了
}
else if (VerbBox1.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽1(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,不要这个词了,免得填到动词槽2了
}
}
if (VerbBox2 == "" && FindWord != "")//动词槽2是空的,FindWord经过动词槽1,没有覆盖或吸收,说明FindWord和动词槽1的词无关,例如FindWord是喜欢
{
VerbBox2 = FindWord;//找到的第2个词,放入动词槽
FindWord = "";//置空,免得填到动词槽3了
}
else if (VerbBox2 != "" && FindWord != "")//动词槽2已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox2))//覆盖:例如找到的词(FindWord)是敲打,动词槽2(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox2 = FindWord;//词语槽2的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽3了
}
else if (VerbBox2.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽2(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,免得填到词语槽3了
}
}
if (VerbBox3 == "" && FindWord != "")//动词槽3是空的,FindWord经过动词槽1和2,没有覆盖或吸收,说明FindWord和动词槽1、2的词无关,例如FindWord是喜欢
{
VerbBox3 = FindWord;//找到的第3个词,放入词语槽
FindWord = "";//置空,免得填到词语槽4了
}
else if (VerbBox3 != "" && FindWord != "")//动词槽3已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox3))//覆盖:例如找到的词(FindWord)是敲打,动词槽3(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox3 = FindWord;//词语槽3的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽4了
}
else if (VerbBox3.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽3(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,免得填到词语槽4了
}
}
if (VerbBox4 == "" && FindWord != "")//动词槽4是空的,FindWord经过动词槽1、2、3,没有覆盖或吸收,说明FindWord和动词槽1、2、3的词无关,例如FindWord是喜欢
{
VerbBox4 = FindWord;//找到的第4个词,放入词语槽
FindWord = "";//置空
}
else if (VerbBox4 != "" && FindWord != "")//动词槽4已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox4))//覆盖:例如找到的词(FindWord)是敲打,动词槽4(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox4 = FindWord;//词语槽4的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空
}
else if (VerbBox4.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽4(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空
}
}
/*
“敲打”这个词,会找到三个动词:敲、打、敲打
先找到第一个词:敲,放入VerbBox1
再找到第二个词:打,放入VerbBox2
再找到第三个词:敲打,会覆盖VerbBox1的“敲”字,但却无法覆盖VerbBox2的“打”字
因此程序做一些改进。
*/
if (VerbBox1.Contains(VerbBox2))//VerbBox1包含了VerbBox2
{
VerbBox2 = "";
if (VerbBox3 != "")
{
VerbBox2 = VerbBox3;
VerbBox3 = "";
}
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";
}
}
if (VerbBox2.Contains(VerbBox3))//VerbBox2包含了VerbBox3
{
VerbBox3 = "";
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";
}
}
if (VerbBox3.Contains(VerbBox4))//VerbBox3包含了VerbBox4
{
VerbBox4 = "";
}
}
bool de(string str,string word)
{
/*
熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
UnityEngine.Debug.Log(res);//显示:的
以上注释掉的内容只是解释原理,下面是运行程序:
*/
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLastChar = str.IndexOf(word) + word.Length;
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
if (res == "的")
{
return true;
}
else
{
return false;
}
}
bool VerbJudge(string str,string word)
{
/*
“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 学 | r1 | 生 |
+----------+---------+--------------+
| 压 | l1 | 气 |
+----------+---------+--------------+
word_col:判断这个字是动词还是名词,也就是辨析字。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。
“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
不容易理解的一处:
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 吹 | l1 | 电 |
+----------+---------+--------------+
“吹”字本身做动词,但在“电吹风”这个词里做名词,但我不用把“电吹风”这个三个字都判断,我只要判断“电吹”两个字就可以了。
遇到单字动词的时候,先看这个字是否在词性辨析表里,
如果在,type_col要求是r1(right1,就是要辨析的字的右边1个字符),那就看句子中要辨析的字的右边1个字符是不是符合词性表中的字,
如果符合,要辨析的字就是名词,而不是动词了。
例如学生看书,这句话先找到了动词“学”,在词性辨析表里,“学”字的type_col是r1,content_col是“生”字,
那就在句子中,看“学”字右边的1个字符是不是“生”字,如果是,“学”字就不做动词,而做名词了。
一个要辨析的字,type_col有四种可能:r1、r2、l1、l2,也就是右边1个字,右边2个字,左边1个字,左边2个字,那就要会四个方法:
符合r1:找辨析字右边1个字符:res = str.Substring(str.IndexOf(word) + word.Length, 1);
符合r2:找辨析字右边2个字符:res = str.Substring(str.IndexOf(word) + word.Length, 2);
符合l1:找辨析字左边1个字符:res = str.Substring(str.IndexOf(word) - 1, 1);
符合l2:找辨析字左边2个字符:res = str.Substring(str.IndexOf(word) - 2, 1);
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
res = str.Substring(str.IndexOf(word) + word.Length, 1);//变化形式
}
UnityEngine.Debug.Log(res);//显示:的
//指定词语左边1个字符
res = str.Substring(index - 1, 1);
res = str.Substring(str.IndexOf(word) - 1, 1);//变化形式
UnityEngine.Debug.Log(res);//显示:吃
以上注释掉的内容,只是解释原理,下面是运行程序:
*/
string[] TypeCol = new string[100];//把词性辨析表的辨析字对应的type_col值填充此数组
string[] ContentCol = new string[100];//把词性辨析表的辨析字对应的content_col值填充此数组
string res = "";//截取的字符
bool shima = true;//默认判断是动词
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
//字符型变量要有引号,数字型变量不需要引号
//word是变量,动态的,不能直接放到sql语句里面
string sqlQuery = "select type_col,content_col from verb_judge where word_col = '" + word + "'";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充词性辨析数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
//查询了2列(type_col和content_col),所以返回的结果集有2列,分别用GetValue(0)和GetValue(1)
TypeCol[i] = dbReader.GetValue(0).ToString();//返回的结果集的第1列
ContentCol[i] = dbReader.GetValue(1).ToString();//返回的结果集的第2列
i++;//虽然定义数组长度为10,但i不一定填满了10
}
dbReader.Close();
dbConnection.Close();
if (i > 0)//在词性辨析表里找到内容了,否则i还是默认的0
{
for (int n = 0; n < i; n++)//遍历词性辨析表找到的各种结果
{
if (TypeCol[n] == "r1")//right1:右边1个字符
{
if (str.IndexOf(word) + word.Length + 1 <= str.Length)//要往右判断1个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 1);//截取动词右边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "r2")//right2:右边2个字符
{
if (str.IndexOf(word) + word.Length + 2 <= str.Length)//要往右判断2个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 2);//截取动词右边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l1")//left1:左边1个字符
{
if (str.IndexOf(word) - 1 >= 0)//要往左判断1个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 1, 1);//截取动词左边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l2")//left2:左边2个字符
{
if (str.IndexOf(word) - 2 >= 0)//要往左判断2个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 2, 2);//截取动词左边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
}
}
i = 0;
return shima;
}
string SentenceJudge()
{
/*
判断句型:
基本单句有六种句型:
只有性质状态(表语):真漂亮、对啊、太好了。句子里没有谓语动词,其余五种句型里,都有谓语动词。
主语(动作执行者)-谓语(动作):张三摔倒。
主语(动作执行者)-谓语(动作)-宾语(动作对象):猫吃鼠。
主语-谓语(是)-表语(表明主语的身份和性质状态):张三是老师,太阳是美丽的。
双宾语句型:主语(传输的人)-谓语(传输动作)-间接宾语(传输对象)-直接宾语(传输的事物):张三给李四苹果,张三教李四数学。
宾语补足语句型:主语-谓语(例如把、使、让)-宾语-宾语补足语(做什么):张三让李四跳舞,张三把房间弄脏了。
前面只说了主谓宾句型,还要处理其它句型。
双宾语句型:
双宾语句型的谓语动词后面有两个名词,例如张三给李四苹果,李四是间接宾语(名词),苹果是直接宾语(名词)。
但是有两个名词的就是双宾语句型吗?不是的。例如张三喜欢足球学校。谓语动词后面有两个名词:足球、学校,但显然足球学校是一个整体名词,也就是主谓宾句型,而不是双宾语句型。因此判断双宾语句型,还要看谓语动词是不是适合双宾语句型的。
双宾语句型的谓语动词主要是传输事物的动词:给、送给、教。
那么谓语动词是双宾语句型的动词(例如给、教),且谓语动词后面有两个名词(体现为谓语动词右边的语句处理时,名词槽NounBox有两个名词,NounBox1和NounBox2都有值),就可以判断为双宾语句型。
还有,像“足球学校”这样两个名词连在一起,就要合并成一个名词,作为主语或宾语。
仅从双宾语句型的标志动词“教”判断双宾语句型,不一定准确,例如“他教我数学”是双宾语句型,但“他教书”就不是双宾语句型,所以还要根据宾语名词的数量,来判断到底是不是双宾语句型,如果动词右边只有一个名词,例如“他教书”的“书”,句子就不是双宾语句型。所以通过谓语动词判断一个句子是双宾语句型后,根据找到的名词数量,例如只有一个宾语名词,那么就要把双宾语句型,修正回主谓宾句型。
名词次序:间接宾语在直接宾语之前,所以找到两个名词,次序在前面的那个名词,是间接宾语,次序在后面的那个名词是直接宾语。
宾语补足语句型:
和主谓宾句型不同,宾语补足语句型含有主谓宾句型的部分,但宾语后面还有个动作(动词),也就是宾语补足语。
因此看宾语后面是否还有动词,是判断宾语补足语句型的方法。
但是有两个动词就麻烦了,如何判断这个动词是谓语动词还是宾语补足语动词呢?那就需要先把所有动词找出来,如果是宾语补足语动词,那么这个动词在谓语动词的后面,如果是谓语动词,则在前面。
既然要存放多个动词进行判断,就要有动词槽(VerbBox)。
动词次序:谓语动词在宾语补足语动词之前,所以找到两个动词,词语次序在前面的是谓语动词,词语次序在后面的是宾语补足语动词。
宾语补足语动词后面还有个名词,宾语补足语动词和这个名词合并在一起,作为宾语补足语。例如他让我打扫教室。如果宾语补足语只是“打扫”,话就说不清楚了。但是有些宾语补足语,就只有动词,后面没有名词,例如“他让我跳舞”就只有“跳舞”这一个动词,“跳舞”这个词后面没有名词,因为“跳舞”是不及物动词。
双宾语句型和宾语补足语句型,都是由主谓宾句型拓展而成的。双宾语句型在主谓宾句型的基础上,多加了一个宾语。宾语补足语句型在主谓宾句型的基础上,多加了一个动词(宾语补足语)。所以先完成主谓宾句型,再根据是否有拓展,来判断是不是双宾语句型或宾语补足语句型。
在主谓宾句型的基础上,如果没有宾语,就是主谓句型。如果没有主语,就是省略主语,例如对一个人喊“过来”,这句话的全句显然是“你过来”。
*/
if (VerbBox1 == "")//没有动词
{
return "只有性质状态";//只有性质状态的句型
}
else if (VerbBox1 != "" && VerbBox2 == "")//有1个动词
{
if (VerbBox1 == "给" || VerbBox1 == "送" || VerbBox1 == "送给" || VerbBox1 == "教")//双宾语句型的常见动词(标志词)
{
return "双宾语";//双宾语句型
}
else
{
return "主谓宾";//主谓宾句型
}
}
else if (VerbBox1 != "" && VerbBox2 != "")//有2个动词
{
return "宾语补足语";//宾语补足语句型
}
else
{
return "其它";
}
}
void NounOrder()
{
//名词排序
if (NounBox1 != "" && NounBox2 != "")//招到了2个名词,放在NounBox1和NounBox2
{
string temp = "";//临时变量
if (shuru.IndexOf(NounBox1) > shuru.IndexOf(NounBox2))//如果NounBox1的名词在句子中的位置大于NounBox2的名词在句子中的位置
{
//交换位置,在句子中位置小的名词放前面,从而确保双宾语句型时,NounBox1放的是间接宾语,NounBox2放的是直接宾语,毕竟间接宾语在直接宾语前面
temp = NounBox1;
NounBox1 = NounBox2;
NounBox2 = temp;
}
FindJianObject = NounBox1;
FindZhiObject = NounBox2;
}
}
void NounJoin()
{
/*
名词合并:例如“足球学校”这个词,会被当成两个名词“足球”和“学校”。但实际中,要把它们合并成一个组合名词,作为主语或宾语。
前面说了判断两个字符之间的内容,如果两个字符(词语)是连续的,那么这两个词语之间的内容为空。
示例:
//截取两个指定字符之间的全部字符
string str = "白色的猫嘲笑黑色的鼠";//全句
string res = "";//结果
string word1 = "的猫";
string word2 = "的鼠";
int Word1LastIndex = str.IndexOf(word1) + word1.Length;
int Word2StartIndex = str.IndexOf(word2);
res = str.Substring(Word1LastIndex, Word2StartIndex - Word1LastIndex);
res = str.Substring(str.IndexOf(word1) + word1.Length, str.IndexOf(word2) - (str.IndexOf(word1) + word1.Length));//展开形式
if (res == "")
{
UnityEngine.Debug.Log("连续");
}
else
{
UnityEngine.Debug.Log("不连续");
}
*/
string res;
//判断NounBox1和NounBox2的名词是否需要合并
if (NounBox1 != "" && NounBox2 != "")
{
res = "";
//判断NounBox1和NounBox2之间是否有内容,如果没内容(res为空),就说明NounBox1和NounBox2是连续的名词(中间没有字符间隔),需要合并
res = shuru.Substring(shuru.IndexOf(NounBox1) + NounBox1.Length, shuru.IndexOf(NounBox2) - (shuru.IndexOf(NounBox1) + NounBox1.Length));
if (res == "")
{
NounBox1 = NounBox1 + NounBox2;//名词合并
NounBox2 = "";//合并后,置空
if (NounBox3 != "")
{
NounBox2 = NounBox3;//填补置空的值,否则NounBox1有值,NounBox2为空,NounBox3又有值,就间隔了
NounBox3 = "";//合并后,置空
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";//合并后,置空
}
}
}
}
/*
//判断NounBox2和NounBox3的名词是否需要合并
if (NounBox2 != "" && NounBox3 != "")
{
res = "";
//判断NounBox2和NounBox3之间是否有内容,如果没内容(res为空),就说明NounBox2和NounBox3是连续的名词,需要合并
res = shuru.Substring(shuru.IndexOf(NounBox2) + NounBox2.Length, shuru.IndexOf(NounBox3) - (shuru.IndexOf(NounBox2) + NounBox2.Length));
if (res == "")
{
NounBox2 = NounBox2 + NounBox3;//名词合并
NounBox3 = "";//合并后,置空
if (NounBox4 != "")
{
NounBox3 = NounBox4;//填补置空的值
NounBox4 = "";//合并后,置空
}
}
}
//判断NounBox3和NounBox4的名词是否需要合并
if (NounBox3 != "" && NounBox4 != "")
{
res = "";
//判断NounBox3和NounBox4之间是否有内容,如果没内容(res为空),就说明NounBox3和NounBox4是连续的名词,需要合并
res = shuru.Substring(shuru.IndexOf(NounBox3) + NounBox3.Length, shuru.IndexOf(NounBox4) - (shuru.IndexOf(NounBox3) + NounBox3.Length));
if (res == "")
{
NounBox3 = NounBox3 + NounBox4;//名词合并
NounBox4 = "";//合并后,置空
}
}
*/
}
void VerbOrder()
{
/*
动词排序:
如果不排序会怎样?句子中找到的第一个动词,可能不是谓语动词,而是宾语补足语动词,以宾语补足语动词分割句子,就错了。
谓语动词和宾语补足语动词,先找到哪个,取决于这两个词,谁在动词表前面排序,而动词的排序是不可知的,或许按笔划排序,或者按首字母排序
*/
string temp = "";//临时变量
if (VerbBox1 != "" && VerbBox2 != "")//招到了个动词,放在VerbBox1和VerbBox2
{
if (shuru.IndexOf(VerbBox1) > shuru.IndexOf(VerbBox2))//如果VerbBox1的动词在句子中的位置大于VerbBox2的动词在句子中的位置
{
//交换位置,在句子中位置小动词的放前面,从而确保VerbBox1放的是谓语动词,而宾语补足语动词放到VerbBox2
temp = VerbBox1;
VerbBox1 = VerbBox2;
VerbBox2 = temp;
}
}
if (VerbBox3 != "")
{
if (shuru.IndexOf(VerbBox1) > shuru.IndexOf(VerbBox3))
{
temp = VerbBox1;
VerbBox1 = VerbBox3;
VerbBox3 = temp;
}
if (shuru.IndexOf(VerbBox2) > shuru.IndexOf(VerbBox3))
{
temp = VerbBox2;
VerbBox2 = VerbBox3;
VerbBox3 = temp;
}
}
FindVerb = VerbBox1;
}
void VerbJoin()
{
//动词合并:例如“应该爱”是两个动词:情态动词“应该”和普通动词“爱”,应该合并成一个动词
string res;
//判断VerbBox1和VerbBox2的动词是否需要合并
if (VerbBox1 != "" && VerbBox2 != "")
{
res = "";
//判断VerbBox1和VerbBox2之间是否有内容,如果没内容(res为空),就说明VerbBox1和VerbBox2是连续的动词(中间没有字符间隔),需要合并
res = shuru.Substring(shuru.IndexOf(VerbBox1) + VerbBox1.Length, shuru.IndexOf(VerbBox2) - (shuru.IndexOf(VerbBox1) + VerbBox1.Length));
if (res == "")
{
VerbBox1 = VerbBox1 + VerbBox2;//名词合并
FindVerb = VerbBox1;
VerbBox2 = "";//合并后,置空
if (VerbBox3 != "")
{
VerbBox2 = VerbBox3;//填补置空的值,否则VerbBox1有值,VerbBox2为空,VerbBox3又有值,就间隔了
VerbBox3 = "";//合并后,置空
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";//合并后,置空
}
}
}
}
}
void VerbRateJudge()
{
/*
动词前面是否有否定词,也很重要。
例如“他爱猫”和“他不爱猫”,虽然谓语动词都是“爱”字,但前面加个“不”字,意义就相反了。所以看谓语动词前面是否有否定词,是很重要的事。
谓语动词前面的否定词,一般有不、不要、不可以、不应该、不能、别。
还有不确定肯定还是否定动词,例如“他不一定去”,“去”字是动词,但是动词前的“不一定”,并不像是“不”字那样对动词进行否定,而是对动词既不像是肯定,也不像是否定,而是不确定。
因此对每句话的谓语动词,都要加一个性质:肯定、否定、不确定。
但不确定,有时候偏向于肯定,例如“他可能去”。有时候不确定偏向于否定,例如“他不太可能去”以及“他或许不去”。
那么动词发生概率分为五种:肯定、偏向肯定、不确定、偏向否定、否定。
这其实就是在分析事情(谓语动词)发生的概率,这在概率分析上有用。
指定词语左边1个字符:str.Substring(str.IndexOf(word) - 1, 1);
指定词语左边1个字符:str.Substring(str.IndexOf(word) - 2, 1);
*/
VerbRate = "肯定";//默认值:肯定
string temp = "";//临时变量
//先判断谓语动词左边的1个字符,是否是否定词
temp = shuru.Substring(shuru.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不"))
{
VerbRate = "否定";
}
else if(temp.Contains("别"))
{
VerbRate = "否定";
}
//判断谓语动词左边的2个字符,是否是否定词
temp = shuru.Substring(shuru.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不要"))
{
VerbRate = "否定";
}
else if (temp.Contains("不能"))
{
VerbRate = "否定";
}
else if (temp.Contains("可能"))
{
VerbRate = "不确定";
}
else if (temp.Contains("或许"))
{
VerbRate = "不确定";
}
//判断谓语动词左边的3个字符,是否是否定词
temp = shuru.Substring(shuru.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不可以"))
{
VerbRate = "否定";
}
else if (temp.Contains("不应该"))
{
VerbRate = "否定";
}
}
//显示最终输出结果
void ShowResult()
{
//tmpText.text = "";//Text Mesh Pro控件显示文字
UnityEngine.Debug.Log("句型:" + SentenceType);
if (SentenceType == "主谓宾")//主谓宾句型
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("宾语:" + FindObject);
UnityEngine.Debug.Log("语态:" + yutai);
}
else if (SentenceType == "双宾语")
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("间接宾语:" + FindJianObject);
UnityEngine.Debug.Log("直接宾语:" + FindZhiObject);
}
else if (SentenceType == "宾语补足语")
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("宾语:" + FindObject);
UnityEngine.Debug.Log("宾语补足语动词:" + FindBuVerb);
UnityEngine.Debug.Log("宾语补足语名词:" + FindBuNoun);
}
else if (SentenceType == "只有性质状态")
{
UnityEngine.Debug.Log("只有性质状态:" + shuru);
}
UnityEngine.Debug.Log("动词发生概率:" + VerbRate);
//清空变量
FindSubject = "";
FindVerb = "";
FindObject = "";
FindBuVerb = "";
FindBuNoun = "";
FindJianObject = "";
FindZhiObject = "";
yutai = "";
}
}
第四章
在这一章:
第一,一次可以输入多句话,但只能用逗号或句号隔开,不能用问号和感叹号分隔句子。
第二,对主谓宾结构可以分析出定语(形容词、数词、名词所有格),但双宾语句型和宾语补足语句型,还没有做定语分析程序,而且数词只能用阿拉伯数字,也就是1、2、3这类数字,还不能用汉字型数字。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;//Canvas框显示输入框和输出框所需
using TMPro;//Text Mesh Pro文字控件所需
using Mono.Data.Sqlite;//连接sqlite数据库所需
using System.Text.RegularExpressions;//正则表达式找出数字所需
public class sqlitecon : MonoBehaviour
{
//输入和输出
public TMP_InputField inputField;//输入框对象(把层级面板上的输入框控件拖动到此框里)
string shuru = "";//输入框内容
//public TMP_Text tmpText;//输出框对象(把层级面板上的输出框控件拖动到此框里)
//string mes;//输出框内容
//词库
string[] noun = new string[7128];//名词数组,名词数量7128(数据库增加名词后,此处也要修改,以免造成溢出)
string[] verb = new string[5886];//动词数组,动词数量5886(数据库增加动词后,此处也要修改,以免造成溢出)
string[] adj = new string[1777];//形容词数组,形容词数量1777(数据库增加形容词后,此处也要修改,以免造成溢出)
int i = 0;//数组用的循环变量
//按标点符号分割句子
string dan = "";//按标点符号分割出的基本单句
string[] danju = new string[100];//单句的数组储存
int dan_num = 1;//第几个单句
//基本单句的语法结构
string FindSubject = "";//主语
string FindVerb = "";//谓语动词
string FindObject = "";//宾语
string FindBuVerb = "";//宾语补足语的动词
string FindBuNoun = "";//宾语补足语的名词
string FindJianObject = "";//间接宾语
string FindZhiObject = "";//直接宾语
//名词所有格(例如张三的猫,张三就是名词所有格,“的”字就不写了)
string SubjectSuoyouge = "";//主语的名词所有格
string ObjectSuoyouge = "";//宾语的名词所有格
//string JianSuoyouge = "";//间接宾语的名词所有格
//string ZhiSuoyouge = "";//直接宾语的名词所有格
//string BuSuoyouge = "";//宾语补足语的名词所有格
string TempSuoyouge = "";//临时存放名词所有格
//形容词
string SubjectAdj = "";//主语的形容词
string ObjectAdj = "";//宾语的形容词
//string JianAdj = "";//间接宾语的形容词
//string ZhiAdj = "";//直接宾语的形容词
//string BuAdj = "";//宾语补足语的形容词
//数词
string SubjectNum = "";//主语的数词
string ObjectNum = "";//宾语的数词
//string JianNum = "";//间接宾语的数词
//string ZhiNum = "";//直接宾语的数词
//string BuNum = "";//宾语补足语的数词
//语法结构的相关描述
string SentenceType = "";//句型
string yutai = "";//语态:主动语态还是被动语态
string VerbRate = "";//动词发生概率:肯定、偏向肯定、不确定、偏向否定、否定
//名词槽(名词之间相互覆盖时用)
string NounBox1 = "";//名词槽1
string NounBox2 = "";//名词槽2
string NounBox3 = "";//名词槽3
string NounBox4 = "";//名词槽4
//动词槽(动词之间相互覆盖时用)
string VerbBox1 = "";//动词槽1
string VerbBox2 = "";//动词槽2
string VerbBox3 = "";//动词槽3
string VerbBox4 = "";//动词槽4
// Start is called before the first frame update
void Start()
{
ciku();//填充词库
inputField.onEndEdit.AddListener(OnInputEndEdit);//输入完成后,对回车键的响应(按回车键发送)
}
// Update is called once per frame
void Update()
{
}
//填充词库(数据库的词库填充到数组中)
void ciku()
{
//生成游戏后,需要把sqlite数据库复制到生成的游戏的文件夹里,那个文件夹自动生成的这个数据库是0kb,无效的,需要重新复制过去
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
string sqlQuery = "SELECT word_col FROM noun";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充名词数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
while (dbReader.Read())
{
noun[i] = dbReader.GetValue(0).ToString();//GetValue(0)表示结果集的第一列,因为只查询了一列,所以返回的结果集就一列
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示名词数量
//填充动词数组
//第一步:sql指令
sqlQuery = "SELECT word_col FROM verb";//sql指令
//第二步:执行指令
//dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充动词数组
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
verb[i] = dbReader.GetValue(0).ToString();
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示动词数量
//填充形容词数组
//第一步:sql指令
sqlQuery = "SELECT word_col FROM adj";//sql指令
//第二步:执行指令
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充动词数组
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
adj[i] = dbReader.GetValue(0).ToString();
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示形容词数量
dbConnection.Close();//关闭数据库连接
}
//输入完成后,按回车键发送,便开始执行此函数
void OnInputEndEdit(string value)
{
shuru = inputField.text;//输入框的内容
SplitSay();//按标点符号,分割输入内容
}
//按标点符号,分割输入内容,分割成基本单句
void SplitSay()
{
/*
输入的内容可能是一大段内容,需要分割成一个个基本单句,从而逐一处理。
基本单句就是主语-谓语-宾语,或主语-谓语-间接宾语-直接宾语,或主语-谓语-宾语-宾语补足语,这类语法上的基本单句。
那就需要按逗号分割句子,按句号分割句子,才能拆分成一个个这样的基本单句。
按逗号分割句子:
string str = "早晨,中午,下午";
string word = ",";
string[] shuzu = str.Split(word);//按word指定的分隔符,分割字符串,并存入数组中
foreach (string part in shuzu)
{
UnityEngine.Debug.Log(part);
}
按逗号和句号分割句子:
string str = "早晨,中午。下午,傍晚";
string word = ",";
string[] shuzu = str.Split(word);//按word指定的分隔符(逗号),分割字符串,并存入数组中
foreach (string part in shuzu)
{
string word2 = "。";
string[] shuzu2 = part.Split(word2);//按word2指定的分隔符(句号),分割字符串,并存入数组中
foreach (string part2 in shuzu2)
{
UnityEngine.Debug.Log(part2);
}
}
计算标点符号的数量:
string str = "早晨,中午。下午,傍晚";
string temp = "";
int dou = 0;//逗号数量
int ju = 0;//句号数量
int str_length = str.Length;//句子长度
temp = str.Replace(",", "");//把逗号替换为空无,就是去掉逗号
int str_length_delete_dou = temp.Length;//去掉逗号后,句子的长度
dou = str_length - str_length_delete_dou;//两者相减,就是逗号的数量
temp = str.Replace("。", "");//把句号替换为空无,就是去掉句号
int str_length_delete_ju = temp.Length;//去掉句号后,句子的长度
ju = str_length - str_length_delete_ju;//两者相减,就是句号的数量
以上注释掉的内容,只是解释说明,下面才是运行的程序:
*/
//计算标点符号的数量
string temp = "";
int dou = 0;//逗号数量
int ju = 0;//句号数量
int str_length = shuru.Length;//句子长度
//计算逗号的数量
temp = shuru.Replace(",", "");//把逗号替换为空无,就是去掉逗号
int str_length_delete_dou = temp.Length;//去掉逗号后,句子的长度
dou = str_length - str_length_delete_dou;//两者相减,就是逗号的数量
//计算句号的数量
temp = shuru.Replace("。", "");//把句号替换为空无,就是去掉句号
int str_length_delete_ju = temp.Length;//去掉句号后,句子的长度
ju = str_length - str_length_delete_ju;//两者相减,就是句号的数量
//按标点符号分割句子
if (dou > 0 || ju > 0)//逗号大于0或句号大于0,就是输入的内容有标点符号
{
string word = ",";//分割符:中文的逗号
string[] shuzu = shuru.Split(word);//按word指定的分隔符(逗号),分割字符串,并存入数组中
foreach (string part in shuzu)//逐个处理
{
string word2 = "。";//分割符:中文的句号
string[] shuzu2 = part.Split(word2);//按word2指定的分隔符(句号),分割字符串,并存入数组中
foreach (string part2 in shuzu2)//逐个处理
{
dan = part2;//基本单句已经分割出来了,在part2里,并赋值给dan(基本单句)
danju[dan_num - 1] = part2;//数组从0开始计算,而danju从1开始计算,所以换算上要减1
ClearData();//清除上次的变量数据
//UnityEngine.Debug.Log("单句:" + dan);
SearchVerb(dan);//找谓语动词(这是单句处理的第一步)
dan = "";
dan_num++;
}
}
}
else//输入的内容,没有标点符号
{
if (shuru != "")//有输入的内容
{
dan = shuru;//输入的内容就是一个基本单句
danju[0] = shuru;
SearchVerb(dan);//找谓语动词
dan = "";
}
}
}
//清除上次循环(基本单句处理)的变量数据
void ClearData()
{
FindSubject = "";//主语
FindVerb = "";//谓语动词
FindObject = "";//宾语
FindBuVerb = "";//宾语补足语的动词
FindBuNoun = "";//宾语补足语的名词
FindJianObject = "";//间接宾语
FindZhiObject = "";//直接宾语
SubjectSuoyouge = "";//主语的名词所有格
ObjectSuoyouge = "";//宾语的名词所有格
TempSuoyouge = "";//临时存放名词所有格
SubjectAdj = "";//主语的形容词
ObjectAdj = "";//宾语的形容词
SubjectNum = "";//主语的数词
ObjectNum = "";//宾语的数词
SentenceType = "";//句型
yutai = "";//语态:主动语态还是被动语态
VerbRate = "";//动词发生概率:肯定、偏向肯定、不确定、偏向否定、否定
NounBox1 = "";//名词槽1
NounBox2 = "";//名词槽2
NounBox3 = "";//名词槽3
NounBox4 = "";//名词槽4
VerbBox1 = "";//动词槽1
VerbBox2 = "";//动词槽2
VerbBox3 = "";//动词槽3
VerbBox4 = "";//动词槽4
i = 0;
}
//找谓语动词
void SearchVerb(string str)
{
string jieguo = "不包含";//默认值是不包含动词
int m = verb.Length;//动词数组的长度,也就是有多少个动词
VerbBox1 = "";
VerbBox2 = "";
VerbBox3 = "";
VerbBox4 = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和动词的包含关系
就是用句子和动词数组的动词,一一比对,来判断是否包含动词
n的值从0逐渐增长到动词数组的动词数量值,这样数组也就经历了所有动词
*/
if (str.Contains(verb[n]))//包含动词
{
if (VerbJudge(str, verb[n]) == true)//是动词,不是名词
{
jieguo = "包含";
FindVerb = verb[n];//找到了动词
VerbCover(str, verb[n]);//把动词放入动词槽里,看看有几个动词
VerbOrder();//动词排序
VerbJoin();//动词结合
}
}
}
if (jieguo == "包含")//包含动词
{
VerbRateJudge();//动词发生概率:肯定、偏向肯定、不确定、偏向否定、否定
SentenceType = SentenceJudge();//判断句型(仅从动词情况来判断句型,还不是完全清楚的判断,之后还需进一步判断)
SplitSentence();//以谓语动词为分割符,来分割句子
}
}
//以谓语动词为分割符,来分割句子
void SplitSentence()
{
/*
对于主谓宾句型,先找出动词,然后以动词为分割符号,分割句子。动词左边分割出的句子的名词就是主语,动词右边分割出的句子的名词就是宾语
先举个例子简单说明一下字符串分割的基本原理:
string str = "白色的猫嘲笑黑色的鼠";//全句
string word = "嘲笑";//指定词
string res = "";//结果
int chang = 0;//全句长度
int index = 0;//指定词语的起始位置
int LastIndex = 0;//指定词语最后一个字符在全句中的位置
int jie = 0;//临时变量
//计算全句长度
chang = str.Length;//显示字符个数,从1开始计算
//计算指定字符在全句中的位置
index = str.IndexOf(word) + 1;//默认从0计算,例如第2个字符,显示为1,而不是2。为了调整为1开始计算,所以加1
//计算指定词语最后一个字符在全句中的位置
LastIndex = str.IndexOf(word) + word.Length;
//截取第3个字符右边的1个字符
Substring(开始位置, 向右截取长度),从1开始计算,不是0
res = str.Substring(3,1); //从第3个字符开始,向右截取1个字符
//截取指定字符右边的全部字符
jie = chang - LastIndex;//截取长度 = 全句长度 - 指定词语最后一个字符的位置长度
res = str.Substring(LastIndex, jie);
res = str.Substring(str.IndexOf(word) + word.Length, str.Length - (str.IndexOf(word) + word.Length));//展开形式
//截取指定字符左边的全部字符
res = str.Substring(0, index);//从句子开始的0位置,截取长度是指定字符的位置长度
res = str.Substring(0, str.IndexOf(word));//变化形式
//截取两个指定字符之间的全部字符
string word1 = "的猫";
string word2 = "的鼠";
int Word1LastIndex = str.IndexOf(word1) + word1.Length;
int Word2StartIndex = str.IndexOf(word2);
res = str.Substring(Word1LastIndex, Word2StartIndex - Word1LastIndex);
res = str.Substring(str.IndexOf(word1) + word1.Length, str.IndexOf(word2) - (str.IndexOf(word1) + word1.Length));//展开形式
//数组形式截取字符
//前面定义了:str = "白色的猫吃黑色的鼠"; word = "吃";
string[] shuzu = str.Split(word);//按指定分割符分割字符串,并存入数组中
UnityEngine.Debug.Log(shuzu[0]);//显示:白色的猫
UnityEngine.Debug.Log(shuzu[1]);//显示:黑色的鼠
//或逐一显示数组全部
foreach (string part in shuzu)
{
UnityEngine.Debug.Log(part);
}
以上注释掉的内容,只是解释原理,下面是运行的程序:
*/
string LeftPart = "";//谓语动词的左边句
string RightPart = "";//谓语动词的右边句
//也可能找到一个动词(主谓宾句型),也可能找到两个动词(宾语补足语句型)
if (VerbBox1 != "" && VerbBox2 == "")//只找到1个动词,那就是谓语动词
{
FindVerb = VerbBox1;
}
else if (VerbBox1 != "" && VerbBox2 != "")//找到2个动词
{
FindVerb = VerbBox1;//位次在前面的动词是谓语动词
FindBuVerb = VerbBox2;//位次在后面的动词是宾语补足语动词
}
//谓语动词左边句(LeftPart)和谓语动词右边句(RightPart)是一个重要的转折,为以后的句子处理奠定了基础
LeftPart = dan.Substring(0, dan.IndexOf(FindVerb));
RightPart = dan.Substring(dan.IndexOf(FindVerb) + FindVerb.Length, dan.Length - (dan.IndexOf(FindVerb) + FindVerb.Length));
/*
例如句子(dan)是白色的猫吃黑色的鼠
find_word:吃
LeftPart:白色的猫
RightPart:黑色的鼠
UnityEngine.Debug.Log(find_verb);//谓语动词
UnityEngine.Debug.Log(LeftPart);//谓语动词的左边句
UnityEngine.Debug.Log(RightPart);//谓语动词的右边句
*/
/*
省略主语有两种情况:一种是主动语态省略主语,例如“跳过去”,全句指“你跳过去”。另一种是被动语态省略主语,例如“张三被打了”,没说谁打了张三,这里张三是宾语。如果说“李四打了张三”,李四就是主语。
被动语态的标志是“被”字,如果没有“被”字,而且省略了主语,就是主动语态省略主语的情况,那么这种情况下,主语应该填什么呢?例如“过来”,一般指“你过来”,但“走吧”一般指“我们走吧”。所以程序要根据具体的动词来判断省略的主语应该填什么。但是动词太多,每个动词都要设置省略的主语判断,太麻烦。所以省略主语,按最通常情况,就默认填“你”字,作为主语。如果主语是“我们”而不是“你”字,就不该省略主语。
被动语态应该还原为主动语态去理解,但被动语态往往没有主语,那么默认主语应该填什么呢?毕竟不知道主语,那就填“事物”这个词作为主语。
程序分析句子时,被动语态的主语位置的词,是宾语。例如“李四被打了”,李四在谓语动词左边句,程序会把李四当成主语,但在被动语态句里,李四不是主语,所以有“被”字的时候,主语要挪动到宾语位置,然后在主语位置补充“事物”这个词,作为主语。
但是有些时候,被动语态的主语是说明了的,例如“李四被张三打了”就还原为主动语态“张三打了李四”,张三做主语,而不是填“事物”做主语。
简而言之,被动语态里,主语放到了宾语位置,宾语放到了主语位置,所以变为主动语态时,要把宾语挪回主语位置,主语挪回宾语位置。
如果被动语态有主语,例如“李四被张三打了”,那么主语(张三)位于“被”字与谓语动词之间。
那么谓语动词左边句中,又分为“被”字左边句和“被”字右边句,被字左边句里的名词是宾语,被字右边句里的名词是主语。
*/
yutai = "主动";//默认主动语态
if (SentenceType == "主谓宾" && dan.Contains("被"))//语句中包含“被”字
{
if (dan.Contains("被子") == false && dan.Contains("被褥") == false)//语句中包含“被”字,但不是“被子”这个名词,才能指被动语态的“被”字
{
yutai = "被动";//被动语态
}
else
{
yutai = "主动";//主动语态
}
}
else//语句中没有包含“被”字
{
yutai = "主动";//主动语态
}
//对谓语动词左边句(LeftPart)的处理
if (LeftPart != "")//谓语动词左边句有内容
{
if (yutai == "主动")//主动语态
{
//找名词(主语)和名词所有格
FindSubject = SearchNoun(LeftPart);//在谓语动词左边句找名词(主语)
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
SubjectSuoyouge = TempSuoyouge;//是主语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(主语的形容词)
SubjectAdj = SearchAdj(LeftPart);
//找数词
SubjectNum = SearchNum(LeftPart);
}
else if (yutai == "被动")//被动语态
{
string bei = "被";
string BeiLeft = "";
string BeiRight = "";
//被字左边句
BeiLeft = LeftPart.Substring(0, LeftPart.IndexOf(bei));
if (BeiLeft != "")
{
FindObject = SearchNoun(BeiLeft);//被字左边句的名词是宾语
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
ObjectSuoyouge = TempSuoyouge;//是宾语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(宾语的形容词)
ObjectAdj = SearchAdj(BeiLeft);
//找数词
ObjectNum = SearchNum(BeiLeft);
}
//被字右边句
BeiRight = LeftPart.Substring(LeftPart.IndexOf(bei) + bei.Length, LeftPart.Length - (LeftPart.IndexOf(bei) + bei.Length));
if (BeiRight != "")
{
FindSubject = SearchNoun(BeiRight);//被字右边句的名词是主语
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
SubjectSuoyouge = TempSuoyouge;//是主语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(主语的形容词)
SubjectAdj = SearchAdj(BeiRight);
//找数词
SubjectNum = SearchNum(BeiRight);
}
//如果没有主语,就填补“事物”这个词作为主语,毕竟被动语态经常没有主语
if (FindSubject == "" || FindSubject == null)//主语为空或主语不存在
{
FindSubject = "事物";
}
}
}
//如果省略主语,则填补省略的主语
if (yutai == "主动")
{
if (FindSubject == "" || FindSubject == null)//主语为空或主语不存在
{
FindSubject = "你";//默认填补“你”字做主语
}
}
//对谓语动词右边句(RightPart)的处理
if (SentenceType == "双宾语")//双宾语句型
{
FindObject = SearchNoun(RightPart);//找名词
//谓语动词右边句里,没有第二个宾语名词,那就不是双宾语
//例如虽然有双宾语句的标志动词“教”字,但他教我数学,是双宾语句,而他教书,是主谓宾句型
if (NounBox2 == "")
{
SentenceType = "主谓宾";
}
else
{
ShowResult();//显示最终输出结果
}
}
if (SentenceType == "主谓宾")//主谓宾句型
{
if (RightPart != "")
{
if (yutai == "主动")
{
//找名词和名词所有格
FindObject = SearchNoun(RightPart);//在谓语动词右边句找名词(宾语)
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
ObjectSuoyouge = TempSuoyouge;//是宾语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(宾语的形容词)
ObjectAdj = SearchAdj(RightPart);
//找数词
ObjectNum = SearchNum(RightPart);
}
}
ShowResult();//显示最终输出结果
}
if (SentenceType == "宾语补足语")//宾语补足语句型
{
//谓语动词到宾语补足语动词之间的部分里的名词,是宾语名词
string temp = "";
//截取谓语动词FindVerb和宾语补足语动词FindBuVerb之间的部分
temp = dan.Substring(dan.IndexOf(FindVerb) + FindVerb.Length, dan.IndexOf(FindBuVerb) - (dan.IndexOf(FindVerb) + FindVerb.Length));
FindObject = SearchNoun(temp);//找名词
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
ObjectSuoyouge = TempSuoyouge;//是宾语的名词所有格
TempSuoyouge = "";//置空
}
//宾语补足语右边句的名词,是宾语补足语名词,而不是宾语名词
int WordLastChar = dan.IndexOf(FindBuVerb) + FindBuVerb.Length;//宾语补足语动词最后一个字符的位置
if (WordLastChar < dan.Length)//宾语补足语动词最后一个字符的位置没有到全句末尾,就是说宾语补足语动词后面还有内容,那就是宾语补足语名词
{
//截取宾语补足语动词右边的内容
FindBuNoun = dan.Substring(dan.IndexOf(FindBuVerb) + FindBuVerb.Length, dan.Length - (dan.IndexOf(FindBuVerb) + FindBuVerb.Length));
//以后再写找宾语补足语名词的名词所有格
}
ShowResult();//显示最终输出结果
}
/*
靠句子包含的词直接与词库的词对比,来找主语(名词)、谓语(动词)、宾语(名词),会有问题:
第一个问题:熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
所以创建一个函数:WordCover(覆盖)。
词语槽(NounBox)存放这些找到词,以实现覆盖和吸收。
第二个问题:熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
对于第二个问题的解决方法:
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
所以创建一个de函数。
第三个问题:“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 学 | r1 | 生 |
+----------+---------+--------------+
| 压 | l1 | 气 |
+----------+---------+--------------+
word_col:判断这个字是动词还是名词。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
所以创建一个VerbJudge函数。
*/
}
//找名词(也包括找名词所有格)
string SearchNoun(string PartSentence)
{
string jieguo = "不包含";//默认值是不包含
int m = noun.Length;//名词数组的长度,也就是有多少个名词
//for循环前,先把词语槽清空,因为for循环时,调用的函数WordCover要用词语槽,来完成词语的覆盖和吸收
NounBox1 = "";
NounBox2 = "";
NounBox3 = "";
NounBox4 = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和名词的包含关系
就是用句子和名词数组的名词,一一比对,来判断是否包含名词
n的值从0逐渐增长到名词数组的名词数量值,这样数组也就经历了所有名词
*/
if (PartSentence.Contains(noun[n]))//包含
{
jieguo = "包含";
if (de(PartSentence, noun[n]) == false)//找到的名词右边的第一个字符不是“的”字,才算是名词,否则是名词所有格
{
NounCover(noun[n]);
}
else//名词右边的第一个字是“的”字,就意味着是名词所有格
{
TempSuoyouge = noun[n];//找到的名词所有格
}
}
}
if (jieguo == "包含")//找到了名词
{
NounOrder();//名词排序
//名词要先排序,才能合并名词,否则“足球”和“学校”的顺序如果变成“学校”和“足球”,那就合并成“学校足球”这个词了,而不是“足球学校”
//如果双宾语句型进行名词合并,就可能会把间接宾语名词和直接宾语名词合并到一起,成为一个名词,就不对了
if (SentenceType != "双宾语")//不是双宾语句型
{
NounJoin();//名词合并,例如把“足球”和“学校”合并成“足球学校”这一个名词
}
else if (SentenceType == "双宾语")//是双宾语句型
{
//但是如果现在处理的是双宾语结构的谓语动词左边句,也就是处理主语,还是可以名词合并的
if (dan.IndexOf(NounBox1) < dan.IndexOf(FindVerb))
{
NounJoin();//名词合并
}
}
return NounBox1;
}
else
{
return "";
}
}
//名词之间的覆盖
void NounCover(string FindWord)
{
/*
熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
词语槽(NounBox)存放这些找到词,以实现覆盖和吸收。
做了4个词语槽(NounBox),为了以后适应复杂的句子,但简单的主谓宾句型,一个词语槽就够了。
*/
if (NounBox1 == "" && FindWord != "")//词语槽还是空的,说明这是找到的第一个词
{
NounBox1 = FindWord;//找到的第1个词,放入词语槽
FindWord = "";//置空,免得填到词语槽2了
}
else if (NounBox1 != "" && FindWord != "")//词语槽1已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox1))//覆盖:例如找到的词(FindWord)是熊猫,词语槽1(NounBox1)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox1 = FindWord;//词语槽1的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽2了
}
else if (NounBox1.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽1(NounBox1)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,不要这个词了,免得填到词语槽2了
}
}
if (NounBox2 == "" && FindWord != "")//词语槽2是空的,FindWord经过词语槽1,没有覆盖或吸收,说明FindWord和词语槽1的词无关,例如FindWord是竹子
{
NounBox2 = FindWord;//找到的第2个词,放入词语槽
FindWord = "";//置空,免得填到词语槽3了
}
else if (NounBox2 != "" && FindWord != "")//词语槽2已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox2))//覆盖:例如找到的词(FindWord)是熊猫,词语槽2(NounBox2)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox2 = FindWord;//词语槽2的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽3了
}
else if (NounBox2.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽2(NounBox2)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽3了
}
}
if (NounBox3 == "" && FindWord != "")//词语槽3是空的,FindWord经过词语槽2,没有覆盖或吸收,说明FindWord和词语槽2的词无关,例如FindWord是竹子
{
NounBox3 = FindWord;//找到的第3个词,放入词语槽
FindWord = "";//置空,免得填到词语槽4了
}
else if (NounBox3 != "" && FindWord != "")//词语槽3已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox3))//覆盖:例如找到的词(FindWord)是熊猫,词语槽3(NounBox3)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox3 = FindWord;//词语槽3的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽4了
}
else if (NounBox3.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽3(NounBox3)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽4了
}
}
if (NounBox4 == "" && FindWord != "")//词语槽4是空的,FindWord经过词语槽3,没有覆盖或吸收,说明FindWord和词语槽3的词无关,例如FindWord是竹子
{
NounBox4 = FindWord;//找到的第4个词,放入词语槽
FindWord = "";//置空
}
else if (NounBox4 != "" && FindWord != "")//词语槽4已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox4))//覆盖:例如找到的词(FindWord)是熊猫,词语槽4(NounBox4)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox4 = FindWord;//词语槽4的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空
}
else if (NounBox4.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽4(NounBox4)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空
}
}
/*
“足球”这个词,会找到三个名词:足、球、足球。
先找到第一个词:足,放入NounBox1。
再找到第二个词:球,放入NounBox2。
再找到第三个词:足球,会覆盖NounBox1的“足”字,但却无法覆盖NounBox2的球字。
因此程序做一些改进。
但如果幸运的:
先找到第一个词:足球,放入NounBox1。
再找到第二个词:足,被NounBox1“足球”这个词吸收,不会进入到NounBox2。
再找到第三个词:球,被NounBox1“足球”这个词吸收,也不会进入到NounBox2。
那么就不用执行下面这段程序了。
先找到那个词是不确定的,词库词语可能按笔画排序,也可能按首字母排序,就不知道先找到那个词了。
如果输入的是“皮球”这个词,而词库里没有“皮球”这个词,但有“皮”字和“球”字这两个词。
那么,NounBox1是“皮”字,NounBox2是“球”字,或NounBox1是“球”字,NounBox2是“皮”字,没有覆盖和吸收。
*/
if (NounBox1.Contains(NounBox2))//NounBox1包含了NounBox2,例如“足球”包含“球”字
{
NounBox2 = "";
if (NounBox3 != "")
{
NounBox2 = NounBox3;
NounBox3 = "";
}
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";
}
}
if (NounBox2.Contains(NounBox3))//NounBox2包含了NounBox3
{
NounBox3 = "";
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";
}
}
if (NounBox3.Contains(NounBox4))//NounBox3包含了NounBox4
{
NounBox4 = "";
}
}
//动词之间的覆盖
void VerbCover(string str,string FindWord)
{
if (VerbBox1 == "" && FindWord != "")//动词槽还是空的,说明这是找到的第一个词
{
VerbBox1 = FindWord;//找到的第1个词,放入动词槽
FindWord = "";//置空,免得填到动词槽2了
}
else if (VerbBox1 != "" && FindWord != "")//动词槽1已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox1))//覆盖:例如找到的词(FindWord)是敲打,动词槽1(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox1 = FindWord;//词语槽1的词:长词覆盖短词,例如“敲打”覆盖“打”
FindWord = "";//置空,免得填到动词槽2了
}
else if (VerbBox1.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽1(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,不要这个词了,免得填到动词槽2了
}
}
if (VerbBox2 == "" && FindWord != "")//动词槽2是空的,FindWord经过动词槽1,没有覆盖或吸收,说明FindWord和动词槽1的词无关,例如FindWord是喜欢
{
VerbBox2 = FindWord;//找到的第2个词,放入动词槽
FindWord = "";//置空,免得填到动词槽3了
}
else if (VerbBox2 != "" && FindWord != "")//动词槽2已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox2))//覆盖:例如找到的词(FindWord)是敲打,动词槽2(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox2 = FindWord;//词语槽2的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽3了
}
else if (VerbBox2.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽2(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,免得填到词语槽3了
}
}
if (VerbBox3 == "" && FindWord != "")//动词槽3是空的,FindWord经过动词槽1和2,没有覆盖或吸收,说明FindWord和动词槽1、2的词无关,例如FindWord是喜欢
{
VerbBox3 = FindWord;//找到的第3个词,放入词语槽
FindWord = "";//置空,免得填到词语槽4了
}
else if (VerbBox3 != "" && FindWord != "")//动词槽3已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox3))//覆盖:例如找到的词(FindWord)是敲打,动词槽3(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox3 = FindWord;//词语槽3的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽4了
}
else if (VerbBox3.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽3(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,免得填到词语槽4了
}
}
if (VerbBox4 == "" && FindWord != "")//动词槽4是空的,FindWord经过动词槽1、2、3,没有覆盖或吸收,说明FindWord和动词槽1、2、3的词无关,例如FindWord是喜欢
{
VerbBox4 = FindWord;//找到的第4个词,放入词语槽
FindWord = "";//置空
}
else if (VerbBox4 != "" && FindWord != "")//动词槽4已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox4))//覆盖:例如找到的词(FindWord)是敲打,动词槽4(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox4 = FindWord;//词语槽4的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空
}
else if (VerbBox4.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽4(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空
}
}
/*
“敲打”这个词,会找到三个动词:敲、打、敲打
先找到第一个词:敲,放入VerbBox1
再找到第二个词:打,放入VerbBox2
再找到第三个词:敲打,会覆盖VerbBox1的“敲”字,但却无法覆盖VerbBox2的“打”字
因此程序做一些改进。
*/
if (VerbBox1.Contains(VerbBox2))//VerbBox1包含了VerbBox2
{
VerbBox2 = "";
if (VerbBox3 != "")
{
VerbBox2 = VerbBox3;
VerbBox3 = "";
}
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";
}
}
if (VerbBox2.Contains(VerbBox3))//VerbBox2包含了VerbBox3
{
VerbBox3 = "";
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";
}
}
if (VerbBox3.Contains(VerbBox4))//VerbBox3包含了VerbBox4
{
VerbBox4 = "";
}
}
//名词后面是否包含“的”字
bool de(string str,string word)
{
/*
熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
UnityEngine.Debug.Log(res);//显示:的
以上注释掉的内容只是解释原理,下面是运行程序:
*/
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLastChar = str.IndexOf(word) + word.Length;
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
if (res == "的")
{
return true;
}
else
{
return false;
}
}
//判断一个字是动词还是名词
bool VerbJudge(string str,string word)
{
/*
“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 学 | r1 | 生 |
+----------+---------+--------------+
| 压 | l1 | 气 |
+----------+---------+--------------+
word_col:判断这个字是动词还是名词,也就是辨析字。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。
“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
不容易理解的一处:
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 吹 | l1 | 电 |
+----------+---------+--------------+
“吹”字本身做动词,但在“电吹风”这个词里做名词,但我不用把“电吹风”这个三个字都判断,我只要判断“电吹”两个字就可以了。
遇到单字动词的时候,先看这个字是否在词性辨析表里,
如果在,type_col要求是r1(right1,就是要辨析的字的右边1个字符),那就看句子中要辨析的字的右边1个字符是不是符合词性表中的字,
如果符合,要辨析的字就是名词,而不是动词了。
例如学生看书,这句话先找到了动词“学”,在词性辨析表里,“学”字的type_col是r1,content_col是“生”字,
那就在句子中,看“学”字右边的1个字符是不是“生”字,如果是,“学”字就不做动词,而做名词了。
一个要辨析的字,type_col有四种可能:r1、r2、l1、l2,也就是右边1个字,右边2个字,左边1个字,左边2个字,那就要会四个方法:
符合r1:找辨析字右边1个字符:res = str.Substring(str.IndexOf(word) + word.Length, 1);
符合r2:找辨析字右边2个字符:res = str.Substring(str.IndexOf(word) + word.Length, 2);
符合l1:找辨析字左边1个字符:res = str.Substring(str.IndexOf(word) - 1, 1);
符合l2:找辨析字左边2个字符:res = str.Substring(str.IndexOf(word) - 2, 1);
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
res = str.Substring(str.IndexOf(word) + word.Length, 1);//变化形式
}
UnityEngine.Debug.Log(res);//显示:的
//指定词语左边1个字符
res = str.Substring(index - 1, 1);
res = str.Substring(str.IndexOf(word) - 1, 1);//变化形式
UnityEngine.Debug.Log(res);//显示:吃
以上注释掉的内容,只是解释原理,下面是运行程序:
*/
string[] TypeCol = new string[100];//把词性辨析表的辨析字对应的type_col值填充此数组
string[] ContentCol = new string[100];//把词性辨析表的辨析字对应的content_col值填充此数组
string res = "";//截取的字符
bool shima = true;//默认判断是动词
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
//字符型变量要有引号,数字型变量不需要引号
//word是变量,动态的,不能直接放到sql语句里面
string sqlQuery = "select type_col,content_col from verb_judge where word_col = '" + word + "'";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充词性辨析数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
//查询了2列(type_col和content_col),所以返回的结果集有2列,分别用GetValue(0)和GetValue(1)
TypeCol[i] = dbReader.GetValue(0).ToString();//返回的结果集的第1列
ContentCol[i] = dbReader.GetValue(1).ToString();//返回的结果集的第2列
i++;//虽然定义数组长度为10,但i不一定填满了10
}
dbReader.Close();
dbConnection.Close();
if (i > 0)//在词性辨析表里找到内容了,否则i还是默认的0
{
for (int n = 0; n < i; n++)//遍历词性辨析表找到的各种结果
{
if (TypeCol[n] == "r1")//right1:右边1个字符
{
if (str.IndexOf(word) + word.Length + 1 <= str.Length)//要往右判断1个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 1);//截取动词右边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "r2")//right2:右边2个字符
{
if (str.IndexOf(word) + word.Length + 2 <= str.Length)//要往右判断2个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 2);//截取动词右边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l1")//left1:左边1个字符
{
if (str.IndexOf(word) - 1 >= 0)//要往左判断1个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 1, 1);//截取动词左边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l2")//left2:左边2个字符
{
if (str.IndexOf(word) - 2 >= 0)//要往左判断2个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 2, 2);//截取动词左边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
}
}
i = 0;
return shima;
}
//判断句型
string SentenceJudge()
{
/*
基本单句有六种句型:
只有性质状态(表语):真漂亮、对啊、太好了。句子里没有谓语动词,其余五种句型里,都有谓语动词。
主语(动作执行者)-谓语(动作):张三摔倒。
主语(动作执行者)-谓语(动作)-宾语(动作对象):猫吃鼠。
主语-谓语(是)-表语(表明主语的身份和性质状态):张三是老师,太阳是美丽的。
双宾语句型:主语(传输的人)-谓语(传输动作)-间接宾语(传输对象)-直接宾语(传输的事物):张三给李四苹果,张三教李四数学。
宾语补足语句型:主语-谓语(例如把、使、让)-宾语-宾语补足语(做什么):张三让李四跳舞,张三把房间弄脏了。
前面只说了主谓宾句型,还要处理其它句型。
双宾语句型:
双宾语句型的谓语动词后面有两个名词,例如张三给李四苹果,李四是间接宾语(名词),苹果是直接宾语(名词)。
但是有两个名词的就是双宾语句型吗?不是的。例如张三喜欢足球学校。谓语动词后面有两个名词:足球、学校,但显然足球学校是一个整体名词,也就是主谓宾句型,而不是双宾语句型。因此判断双宾语句型,还要看谓语动词是不是适合双宾语句型的。
双宾语句型的谓语动词主要是传输事物的动词:给、送给、教。
那么谓语动词是双宾语句型的动词(例如给、教),且谓语动词后面有两个名词(体现为谓语动词右边的语句处理时,名词槽NounBox有两个名词,NounBox1和NounBox2都有值),就可以判断为双宾语句型。
还有,像“足球学校”这样两个名词连在一起,就要合并成一个名词,作为主语或宾语。
仅从双宾语句型的标志动词“教”判断双宾语句型,不一定准确,例如“他教我数学”是双宾语句型,但“他教书”就不是双宾语句型,所以还要根据宾语名词的数量,来判断到底是不是双宾语句型,如果动词右边只有一个名词,例如“他教书”的“书”,句子就不是双宾语句型。所以通过谓语动词判断一个句子是双宾语句型后,根据找到的名词数量,例如只有一个宾语名词,那么就要把双宾语句型,修正回主谓宾句型。
名词次序:间接宾语在直接宾语之前,所以找到两个名词,次序在前面的那个名词,是间接宾语,次序在后面的那个名词是直接宾语。
宾语补足语句型:
和主谓宾句型不同,宾语补足语句型含有主谓宾句型的部分,但宾语后面还有个动作(动词),也就是宾语补足语。
因此看宾语后面是否还有动词,是判断宾语补足语句型的方法。
但是有两个动词就麻烦了,如何判断这个动词是谓语动词还是宾语补足语动词呢?那就需要先把所有动词找出来,如果是宾语补足语动词,那么这个动词在谓语动词的后面,如果是谓语动词,则在前面。
既然要存放多个动词进行判断,就要有动词槽(VerbBox)。
动词次序:谓语动词在宾语补足语动词之前,所以找到两个动词,词语次序在前面的是谓语动词,词语次序在后面的是宾语补足语动词。
宾语补足语动词后面还有个名词,宾语补足语动词和这个名词合并在一起,作为宾语补足语。例如他让我打扫教室。如果宾语补足语只是“打扫”,话就说不清楚了。但是有些宾语补足语,就只有动词,后面没有名词,例如“他让我跳舞”就只有“跳舞”这一个动词,“跳舞”这个词后面没有名词,因为“跳舞”是不及物动词。
双宾语句型和宾语补足语句型,都是由主谓宾句型拓展而成的。双宾语句型在主谓宾句型的基础上,多加了一个宾语。宾语补足语句型在主谓宾句型的基础上,多加了一个动词(宾语补足语)。所以先完成主谓宾句型,再根据是否有拓展,来判断是不是双宾语句型或宾语补足语句型。
在主谓宾句型的基础上,如果没有宾语,就是主谓句型。如果没有主语,就是省略主语,例如对一个人喊“过来”,这句话的全句显然是“你过来”。
*/
if (VerbBox1 == "")//没有动词
{
return "只有性质状态";//只有性质状态的句型
}
else if (VerbBox1 != "" && VerbBox2 == "")//有1个动词
{
if (VerbBox1 == "给" || VerbBox1 == "送" || VerbBox1 == "送给" || VerbBox1 == "教")//双宾语句型的常见动词(标志词)
{
return "双宾语";//双宾语句型
}
else
{
return "主谓宾";//主谓宾句型
}
}
else if (VerbBox1 != "" && VerbBox2 != "")//有2个动词
{
return "宾语补足语";//宾语补足语句型
}
else
{
return "其它";
}
}
//名词排序
void NounOrder()
{
if (NounBox1 != "" && NounBox2 != "")//招到了2个名词,放在NounBox1和NounBox2
{
string temp = "";//临时变量
if (dan.IndexOf(NounBox1) > dan.IndexOf(NounBox2))//如果NounBox1的名词在句子中的位置大于NounBox2的名词在句子中的位置
{
//交换位置,在句子中位置小的名词放前面,从而确保双宾语句型时,NounBox1放的是间接宾语,NounBox2放的是直接宾语,毕竟间接宾语在直接宾语前面
temp = NounBox1;
NounBox1 = NounBox2;
NounBox2 = temp;
}
FindJianObject = NounBox1;
FindZhiObject = NounBox2;
//间接宾语和直接宾语的名词所有格,之后再做
}
}
//名词结合成名词词组
void NounJoin()
{
/*
名词合并:例如“足球学校”这个词,会被当成两个名词“足球”和“学校”。但实际中,要把它们合并成一个组合名词,作为主语或宾语。
前面说了判断两个字符之间的内容,如果两个字符(词语)是连续的,那么这两个词语之间的内容为空。
示例:
//截取两个指定字符之间的全部字符
string str = "白色的猫嘲笑黑色的鼠";//全句
string res = "";//结果
string word1 = "的猫";
string word2 = "的鼠";
int Word1LastIndex = str.IndexOf(word1) + word1.Length;
int Word2StartIndex = str.IndexOf(word2);
res = str.Substring(Word1LastIndex, Word2StartIndex - Word1LastIndex);
res = str.Substring(str.IndexOf(word1) + word1.Length, str.IndexOf(word2) - (str.IndexOf(word1) + word1.Length));//展开形式
if (res == "")
{
UnityEngine.Debug.Log("连续");
}
else
{
UnityEngine.Debug.Log("不连续");
}
*/
string res;
//判断NounBox1和NounBox2的名词是否需要合并
if (NounBox1 != "" && NounBox2 != "")
{
res = "";
//判断NounBox1和NounBox2之间是否有内容,如果没内容(res为空),就说明NounBox1和NounBox2是连续的名词(中间没有字符间隔),需要合并
res = dan.Substring(dan.IndexOf(NounBox1) + NounBox1.Length, dan.IndexOf(NounBox2) - (dan.IndexOf(NounBox1) + NounBox1.Length));
if (res == "")
{
NounBox1 = NounBox1 + NounBox2;//名词合并
NounBox2 = "";//合并后,置空
if (NounBox3 != "")
{
NounBox2 = NounBox3;//填补置空的值,否则NounBox1有值,NounBox2为空,NounBox3又有值,就间隔了
NounBox3 = "";//合并后,置空
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";//合并后,置空
}
}
}
}
/*
//判断NounBox2和NounBox3的名词是否需要合并
if (NounBox2 != "" && NounBox3 != "")
{
res = "";
//判断NounBox2和NounBox3之间是否有内容,如果没内容(res为空),就说明NounBox2和NounBox3是连续的名词,需要合并
res = dan.Substring(dan.IndexOf(NounBox2) + NounBox2.Length, dan.IndexOf(NounBox3) - (dan.IndexOf(NounBox2) + NounBox2.Length));
if (res == "")
{
NounBox2 = NounBox2 + NounBox3;//名词合并
NounBox3 = "";//合并后,置空
if (NounBox4 != "")
{
NounBox3 = NounBox4;//填补置空的值
NounBox4 = "";//合并后,置空
}
}
}
//判断NounBox3和NounBox4的名词是否需要合并
if (NounBox3 != "" && NounBox4 != "")
{
res = "";
//判断NounBox3和NounBox4之间是否有内容,如果没内容(res为空),就说明NounBox3和NounBox4是连续的名词,需要合并
res = dan.Substring(dan.IndexOf(NounBox3) + NounBox3.Length, dan.IndexOf(NounBox4) - (dan.IndexOf(NounBox3) + NounBox3.Length));
if (res == "")
{
NounBox3 = NounBox3 + NounBox4;//名词合并
NounBox4 = "";//合并后,置空
}
}
*/
}
//动词排序
void VerbOrder()
{
/*
如果不排序会怎样?句子中找到的第一个动词,可能不是谓语动词,而是宾语补足语动词,以宾语补足语动词分割句子,就错了。
谓语动词和宾语补足语动词,先找到哪个,取决于这两个词,谁在动词表前面排序,而动词的排序是不可知的,或许按笔划排序,或者按首字母排序
*/
string temp = "";//临时变量
if (VerbBox1 != "" && VerbBox2 != "")//招到了个动词,放在VerbBox1和VerbBox2
{
if (dan.IndexOf(VerbBox1) > dan.IndexOf(VerbBox2))//如果VerbBox1的动词在句子中的位置大于VerbBox2的动词在句子中的位置
{
//交换位置,在句子中位置小动词的放前面,从而确保VerbBox1放的是谓语动词,而宾语补足语动词放到VerbBox2
temp = VerbBox1;
VerbBox1 = VerbBox2;
VerbBox2 = temp;
}
}
if (VerbBox3 != "")
{
if (dan.IndexOf(VerbBox1) > dan.IndexOf(VerbBox3))
{
temp = VerbBox1;
VerbBox1 = VerbBox3;
VerbBox3 = temp;
}
if (dan.IndexOf(VerbBox2) > dan.IndexOf(VerbBox3))
{
temp = VerbBox2;
VerbBox2 = VerbBox3;
VerbBox3 = temp;
}
}
FindVerb = VerbBox1;
}
//动词结合成动词词组
void VerbJoin()
{
//动词合并:例如“应该爱”是两个动词:情态动词“应该”和普通动词“爱”,应该合并成一个动词
string res;
//判断VerbBox1和VerbBox2的动词是否需要合并
if (VerbBox1 != "" && VerbBox2 != "")
{
res = "";
//判断VerbBox1和VerbBox2之间是否有内容,如果没内容(res为空),就说明VerbBox1和VerbBox2是连续的动词(中间没有字符间隔),需要合并
res = dan.Substring(dan.IndexOf(VerbBox1) + VerbBox1.Length, dan.IndexOf(VerbBox2) - (dan.IndexOf(VerbBox1) + VerbBox1.Length));
if (res == "")
{
VerbBox1 = VerbBox1 + VerbBox2;//名词合并
FindVerb = VerbBox1;
VerbBox2 = "";//合并后,置空
if (VerbBox3 != "")
{
VerbBox2 = VerbBox3;//填补置空的值,否则VerbBox1有值,VerbBox2为空,VerbBox3又有值,就间隔了
VerbBox3 = "";//合并后,置空
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";//合并后,置空
}
}
}
}
}
//谓语动词的发生概率
void VerbRateJudge()
{
/*
动词前面是否有否定词,也很重要。
例如“他爱猫”和“他不爱猫”,虽然谓语动词都是“爱”字,但前面加个“不”字,意义就相反了。所以看谓语动词前面是否有否定词,是很重要的事。
谓语动词前面的否定词,一般有不、不要、不可以、不应该、不能、别。
还有不确定肯定还是否定动词,例如“他不一定去”,“去”字是动词,但是动词前的“不一定”,并不像是“不”字那样对动词进行否定,而是对动词既不像是肯定,也不像是否定,而是不确定。
因此对每句话的谓语动词,都要加一个性质:肯定、否定、不确定。
但不确定,有时候偏向于肯定,例如“他可能去”。有时候不确定偏向于否定,例如“他不太可能去”以及“他或许不去”。
那么动词发生概率分为五种:肯定、偏向肯定、不确定、偏向否定、否定。
这其实就是在分析事情(谓语动词)发生的概率,这在概率分析上有用。
指定词语左边1个字符:str.Substring(str.IndexOf(word) - 1, 1);
指定词语左边1个字符:str.Substring(str.IndexOf(word) - 2, 1);
*/
VerbRate = "肯定";//默认值:肯定
string temp = "";//临时变量
//先判断谓语动词左边的1个字符,是否是否定词
temp = dan.Substring(dan.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不"))
{
VerbRate = "否定";
}
else if(temp.Contains("别"))
{
VerbRate = "否定";
}
//判断谓语动词左边的2个字符,是否是否定词
temp = dan.Substring(dan.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不要"))
{
VerbRate = "否定";
}
else if (temp.Contains("不能"))
{
VerbRate = "否定";
}
else if (temp.Contains("可能"))
{
VerbRate = "不确定";
}
else if (temp.Contains("或许"))
{
VerbRate = "不确定";
}
//判断谓语动词左边的3个字符,是否是否定词
temp = dan.Substring(dan.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不可以"))
{
VerbRate = "否定";
}
else if (temp.Contains("不应该"))
{
VerbRate = "否定";
}
}
//找形容词
string SearchAdj(string str)
{
string jieguo = "不包含";//默认值是不包含
int m = adj.Length;//形容词数组的长度,也就是有多少个形容词
string temp = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和形容词的包含关系
就是用句子和形容词数组的形容词,一一比对,来判断是否包含形容词
n的值从0逐渐增长到形容词数组的形容词数量值,这样数组也就经历了所有形容词
*/
if (str.Contains(adj[n]))//包含
{
jieguo = "包含";
temp = adj[n];
}
}
if (jieguo == "包含")//找到了形容词
{
return temp;
}
else
{
return "";
}
}
//找数词
string SearchNum(string str)
{
/*
找出数字(找出含有1、2、3这样的阿拉伯数字,而不是一、二、三这样的汉字型数字)。
这种找数字方法用到了正则表达式。
replace函数把不是数字的部分变为空无,这样就只剩下数字部分。
*/
string res = "";
res = Regex.Replace(str, @"[^0-9]+", "");
return res;
}
//显示最终输出结果
void ShowResult()
{
UnityEngine.Debug.Log("第" + dan_num + "句:" + danju[dan_num-1]);
UnityEngine.Debug.Log("句型:" + SentenceType);
if (SentenceType == "主谓宾")//主谓宾句型
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("宾语:" + FindObject);
UnityEngine.Debug.Log("语态:" + yutai);
}
else if (SentenceType == "双宾语")
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("间接宾语:" + FindJianObject);
UnityEngine.Debug.Log("直接宾语:" + FindZhiObject);
}
else if (SentenceType == "宾语补足语")
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("宾语:" + FindObject);
UnityEngine.Debug.Log("宾语补足语动词:" + FindBuVerb);
UnityEngine.Debug.Log("宾语补足语名词:" + FindBuNoun);
}
else if (SentenceType == "只有性质状态")
{
UnityEngine.Debug.Log("只有性质状态:" + dan);
}
UnityEngine.Debug.Log("动词发生概率:" + VerbRate);
//显示名词所有格
if (SubjectSuoyouge != "")
{
UnityEngine.Debug.Log("主语的名词所有格:" + SubjectSuoyouge);
}
if (ObjectSuoyouge != "")
{
UnityEngine.Debug.Log("宾语的名词所有格:" + ObjectSuoyouge);
}
/*
if (JianSuoyouge != "")
{
UnityEngine.Debug.Log("间接宾语的名词所有格:" + JianSuoyouge);
}
if (ZhiSuoyouge != "")
{
UnityEngine.Debug.Log("直接宾语的名词所有格:" + ZhiSuoyouge);
}
if (BuSuoyouge != "")
{
UnityEngine.Debug.Log("宾语补足语的名词所有格:" + BuSuoyouge);
}
*/
//显示形容词
if (SubjectAdj != "")
{
UnityEngine.Debug.Log("主语的形容词:" + SubjectAdj);
}
if (ObjectAdj != "")
{
UnityEngine.Debug.Log("宾语的形容词:" + ObjectAdj);
}
/*
if (JianAdj != "")
{
UnityEngine.Debug.Log("间接宾语的形容词:" + JianAdj);
}
if (ZhiAdj != "")
{
UnityEngine.Debug.Log("直接宾语的形容词:" + ZhiAdj);
}
if (BuAdj != "")
{
UnityEngine.Debug.Log("宾语补足语的形容词:" + BuAdj);
}
*/
//显示数词
if (SubjectNum != "")
{
UnityEngine.Debug.Log("主语的数词:" + SubjectNum);
}
if (ObjectNum != "")
{
UnityEngine.Debug.Log("宾语的数词:" + ObjectNum);
}
/*
if (JianNum != "")
{
UnityEngine.Debug.Log("间接宾语的形容词:" + JianNum);
}
if (ZhiNum != "")
{
UnityEngine.Debug.Log("直接宾语的形容词:" + ZhiNum);
}
if (BuNum != "")
{
UnityEngine.Debug.Log("宾语补足语的形容词:" + BuNum);
}
*/
//tmpText.text = mes;
//清空变量
FindSubject = "";
FindVerb = "";
FindObject = "";
FindBuVerb = "";
FindBuNoun = "";
FindJianObject = "";
FindZhiObject = "";
yutai = "";
SubjectSuoyouge = "";
ObjectSuoyouge = "";
/*
JianSuoyouge = "";
ZhiSuoyouge = "";
BuSuoyouge = "";
*/
}
}
第五章
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;//Canvas框显示输入框和输出框所需
using TMPro;//Text Mesh Pro文字控件所需
using Mono.Data.Sqlite;//连接sqlite数据库所需
public class sqlitecon : MonoBehaviour
{
//输入和输出
public TMP_InputField inputField;//输入框对象(把层级面板上的输入框控件拖动到此框里)
string shuru = "";//输入框内容
//public TMP_Text tmpText;//输出框对象(把层级面板上的输出框控件拖动到此框里)
//string mes;//输出框内容
//词库
string[] noun = new string[7128];//名词数组,名词数量7128(数据库增加名词后,此处也要修改,以免造成溢出)
string[] verb = new string[5886];//动词数组,动词数量5886(数据库增加动词后,此处也要修改,以免造成溢出)
string[] adj = new string[1777];//形容词数组,形容词数量1777(数据库增加形容词后,此处也要修改,以免造成溢出)
int i = 0;//数组用的循环变量
//按标点符号分割句子
string dan = "";//按标点符号分割出的基本单句
string[] danju = new string[100];//单句的数组储存
int dan_num = 1;//第几个单句
//基本单句的语法结构
string FindSubject = "";//主语
string FindVerb = "";//谓语动词
string FindObject = "";//宾语
string FindBuVerb = "";//宾语补足语的动词
string FindBuNoun = "";//宾语补足语的名词
string FindJianObject = "";//间接宾语
string FindZhiObject = "";//直接宾语
//名词所有格(例如张三的猫,张三就是名词所有格,“的”字就不写了)
string SubjectSuoyouge = "";//主语的名词所有格
string ObjectSuoyouge = "";//宾语的名词所有格
//string JianSuoyouge = "";//间接宾语的名词所有格
//string ZhiSuoyouge = "";//直接宾语的名词所有格
//string BuSuoyouge = "";//宾语补足语的名词所有格
string TempSuoyouge = "";//临时存放名词所有格
//形容词
string SubjectAdj = "";//主语的形容词
string ObjectAdj = "";//宾语的形容词
//string JianAdj = "";//间接宾语的形容词
//string ZhiAdj = "";//直接宾语的形容词
//string BuAdj = "";//宾语补足语的形容词
//数词
string SubjectNum = "";//主语的数词
string ObjectNum = "";//宾语的数词
//string JianNum = "";//间接宾语的数词
//string ZhiNum = "";//直接宾语的数词
//string BuNum = "";//宾语补足语的数词
//语法结构的相关描述
string SentenceType = "";//句型
string yutai = "";//语态:主动语态还是被动语态
string VerbRate = "";//动词发生概率:肯定、偏向肯定、不确定、偏向否定、否定
//名词槽(名词之间相互覆盖时用)
string NounBox1 = "";//名词槽1
string NounBox2 = "";//名词槽2
string NounBox3 = "";//名词槽3
string NounBox4 = "";//名词槽4
//动词槽(动词之间相互覆盖时用)
string VerbBox1 = "";//动词槽1
string VerbBox2 = "";//动词槽2
string VerbBox3 = "";//动词槽3
string VerbBox4 = "";//动词槽4
//数词和时间
string FindNum = "";//要找的数词的数字
string NumDanwei = "";//数词单位
string FindTime_year = "";//要找的时间:年
string FindTime_month = "";//要找的时间:月
string FindTime_day = "";//要找的时间:日
string FindTime_hour = "";//要找的时间:小时
string FindTime_minute = "";//要找的时间:分钟
string FindTime2 = "";//要找的时间(文字形式,例如下午、星期一)
string num_type = "";//数字类型:阿拉伯数字(例如1、2、3)还是汉字型数字(例如一、二、三)
// Start is called before the first frame update
void Start()
{
ciku();//填充词库
inputField.onEndEdit.AddListener(OnInputEndEdit);//输入完成后,对回车键的响应(按回车键发送)
}
// Update is called once per frame
void Update()
{
}
//填充词库(数据库的词库填充到数组中)
void ciku()
{
//生成游戏后,需要把sqlite数据库复制到生成的游戏的文件夹里,那个文件夹自动生成的这个数据库是0kb,无效的,需要重新复制过去
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
string sqlQuery = "SELECT word_col FROM noun";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充名词数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
while (dbReader.Read())
{
noun[i] = dbReader.GetValue(0).ToString();//GetValue(0)表示结果集的第一列,因为只查询了一列,所以返回的结果集就一列
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示名词数量
//填充动词数组
//第一步:sql指令
sqlQuery = "SELECT word_col FROM verb";//sql指令
//第二步:执行指令
//dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充动词数组
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
verb[i] = dbReader.GetValue(0).ToString();
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示动词数量
//填充形容词数组
//第一步:sql指令
sqlQuery = "SELECT word_col FROM adj";//sql指令
//第二步:执行指令
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充动词数组
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
adj[i] = dbReader.GetValue(0).ToString();
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示形容词数量
dbConnection.Close();//关闭数据库连接
}
//输入完成后,按回车键发送,便开始执行此函数
void OnInputEndEdit(string value)
{
shuru = inputField.text;//输入框的内容
SplitSay();//按标点符号,分割输入内容
}
//按标点符号,分割输入内容,分割成基本单句
void SplitSay()
{
/*
输入的内容可能是一大段内容,需要分割成一个个基本单句,从而逐一处理。
基本单句就是主语-谓语-宾语,或主语-谓语-间接宾语-直接宾语,或主语-谓语-宾语-宾语补足语,这类语法上的基本单句。
那就需要按逗号分割句子,按句号分割句子,才能拆分成一个个这样的基本单句。
按逗号分割句子:
string str = "早晨,中午,下午";
string word = ",";
string[] shuzu = str.Split(word);//按word指定的分隔符,分割字符串,并存入数组中
foreach (string part in shuzu)
{
UnityEngine.Debug.Log(part);
}
按逗号和句号分割句子:
string str = "早晨,中午。下午,傍晚";
string word = ",";
string[] shuzu = str.Split(word);//按word指定的分隔符(逗号),分割字符串,并存入数组中
foreach (string part in shuzu)
{
string word2 = "。";
string[] shuzu2 = part.Split(word2);//按word2指定的分隔符(句号),分割字符串,并存入数组中
foreach (string part2 in shuzu2)
{
UnityEngine.Debug.Log(part2);
}
}
计算标点符号的数量:
string str = "早晨,中午。下午,傍晚";
string temp = "";
int dou = 0;//逗号数量
int ju = 0;//句号数量
int str_length = str.Length;//句子长度
temp = str.Replace(",", "");//把逗号替换为空无,就是去掉逗号
int str_length_delete_dou = temp.Length;//去掉逗号后,句子的长度
dou = str_length - str_length_delete_dou;//两者相减,就是逗号的数量
temp = str.Replace("。", "");//把句号替换为空无,就是去掉句号
int str_length_delete_ju = temp.Length;//去掉句号后,句子的长度
ju = str_length - str_length_delete_ju;//两者相减,就是句号的数量
以上注释掉的内容,只是解释说明,下面才是运行的程序:
*/
//计算标点符号的数量
string temp = "";
int dou = 0;//逗号数量
int ju = 0;//句号数量
int str_length = shuru.Length;//句子长度
//计算逗号的数量
temp = shuru.Replace(",", "");//把逗号替换为空无,就是去掉逗号
int str_length_delete_dou = temp.Length;//去掉逗号后,句子的长度
dou = str_length - str_length_delete_dou;//两者相减,就是逗号的数量
//计算句号的数量
temp = shuru.Replace("。", "");//把句号替换为空无,就是去掉句号
int str_length_delete_ju = temp.Length;//去掉句号后,句子的长度
ju = str_length - str_length_delete_ju;//两者相减,就是句号的数量
//按标点符号分割句子
if (dou > 0 || ju > 0)//逗号大于0或句号大于0,就是输入的内容有标点符号
{
string word = ",";//分割符:中文的逗号
string[] shuzu = shuru.Split(word);//按word指定的分隔符(逗号),分割字符串,并存入数组中
foreach (string part in shuzu)//逐个处理
{
string word2 = "。";//分割符:中文的句号
string[] shuzu2 = part.Split(word2);//按word2指定的分隔符(句号),分割字符串,并存入数组中
foreach (string part2 in shuzu2)//逐个处理
{
dan = part2;//基本单句已经分割出来了,在part2里,并赋值给dan(基本单句)
danju[dan_num - 1] = part2;//数组从0开始计算,而danju从1开始计算,所以换算上要减1
ClearData();//清除上次的变量数据
//UnityEngine.Debug.Log("单句:" + dan);
SearchVerb(dan);//找谓语动词(这是单句处理的第一步)
dan = "";
dan_num++;
}
}
}
else//输入的内容,没有标点符号
{
if (shuru != "")//有输入的内容
{
dan = shuru;//输入的内容就是一个基本单句
danju[0] = shuru;
SearchVerb(dan);//找谓语动词
dan = "";
}
}
}
//清除上次循环(基本单句处理)的变量数据
void ClearData()
{
FindSubject = "";//主语
FindVerb = "";//谓语动词
FindObject = "";//宾语
FindBuVerb = "";//宾语补足语的动词
FindBuNoun = "";//宾语补足语的名词
FindJianObject = "";//间接宾语
FindZhiObject = "";//直接宾语
SubjectSuoyouge = "";//主语的名词所有格
ObjectSuoyouge = "";//宾语的名词所有格
TempSuoyouge = "";//临时存放名词所有格
SubjectAdj = "";//主语的形容词
ObjectAdj = "";//宾语的形容词
SubjectNum = "";//主语的数词
ObjectNum = "";//宾语的数词
SentenceType = "";//句型
yutai = "";//语态:主动语态还是被动语态
VerbRate = "";//动词发生概率:肯定、偏向肯定、不确定、偏向否定、否定
NounBox1 = "";//名词槽1
NounBox2 = "";//名词槽2
NounBox3 = "";//名词槽3
NounBox4 = "";//名词槽4
VerbBox1 = "";//动词槽1
VerbBox2 = "";//动词槽2
VerbBox3 = "";//动词槽3
VerbBox4 = "";//动词槽4
FindNum = "";
NumDanwei = "";
num_type = "";
i = 0;
}
//找谓语动词
void SearchVerb(string str)
{
string jieguo = "不包含";//默认值是不包含动词
int m = verb.Length;//动词数组的长度,也就是有多少个动词
VerbBox1 = "";
VerbBox2 = "";
VerbBox3 = "";
VerbBox4 = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和动词的包含关系
就是用句子和动词数组的动词,一一比对,来判断是否包含动词
n的值从0逐渐增长到动词数组的动词数量值,这样数组也就经历了所有动词
*/
if (str.Contains(verb[n]))//包含动词
{
if (VerbJudge(str, verb[n]) == true)//是动词,不是名词
{
jieguo = "包含";
FindVerb = verb[n];//找到了动词
VerbCover(str, verb[n]);//把动词放入动词槽里,看看有几个动词
VerbOrder();//动词排序
VerbJoin();//动词结合
}
}
}
if (jieguo == "包含")//包含动词
{
VerbRateJudge();//动词发生概率:肯定、偏向肯定、不确定、偏向否定、否定
SentenceType = SentenceJudge();//判断句型(仅从动词情况来判断句型,还不是完全清楚的判断,之后还需进一步判断)
SplitSentence();//以谓语动词为分割符,来分割句子
}
}
//以谓语动词为分割符,来分割句子
void SplitSentence()
{
/*
对于主谓宾句型,先找出动词,然后以动词为分割符号,分割句子。动词左边分割出的句子的名词就是主语,动词右边分割出的句子的名词就是宾语
先举个例子简单说明一下字符串分割的基本原理:
string str = "白色的猫嘲笑黑色的鼠";//全句
string word = "嘲笑";//指定词
string res = "";//结果
int chang = 0;//全句长度
int index = 0;//指定词语的起始位置
int LastIndex = 0;//指定词语最后一个字符在全句中的位置
int jie = 0;//临时变量
//计算全句长度
chang = str.Length;//显示字符个数,从1开始计算
//计算指定字符在全句中的位置
index = str.IndexOf(word) + 1;//默认从0计算,例如第2个字符,显示为1,而不是2。为了调整为1开始计算,所以加1
//计算指定词语最后一个字符在全句中的位置
LastIndex = str.IndexOf(word) + word.Length;
//截取第3个字符右边的1个字符
Substring(开始位置, 向右截取长度),从1开始计算,不是0
res = str.Substring(3,1); //从第3个字符开始,向右截取1个字符
//截取指定字符右边的全部字符
jie = chang - LastIndex;//截取长度 = 全句长度 - 指定词语最后一个字符的位置长度
res = str.Substring(LastIndex, jie);
res = str.Substring(str.IndexOf(word) + word.Length, str.Length - (str.IndexOf(word) + word.Length));//展开形式
//截取指定字符左边的全部字符
res = str.Substring(0, index);//从句子开始的0位置,截取长度是指定字符的位置长度
res = str.Substring(0, str.IndexOf(word));//变化形式
//截取两个指定字符之间的全部字符
string word1 = "的猫";
string word2 = "的鼠";
int Word1LastIndex = str.IndexOf(word1) + word1.Length;
int Word2StartIndex = str.IndexOf(word2);
res = str.Substring(Word1LastIndex, Word2StartIndex - Word1LastIndex);
res = str.Substring(str.IndexOf(word1) + word1.Length, str.IndexOf(word2) - (str.IndexOf(word1) + word1.Length));//展开形式
//数组形式截取字符
//前面定义了:str = "白色的猫吃黑色的鼠"; word = "吃";
string[] shuzu = str.Split(word);//按指定分割符分割字符串,并存入数组中
UnityEngine.Debug.Log(shuzu[0]);//显示:白色的猫
UnityEngine.Debug.Log(shuzu[1]);//显示:黑色的鼠
//或逐一显示数组全部
foreach (string part in shuzu)
{
UnityEngine.Debug.Log(part);
}
以上注释掉的内容,只是解释原理,下面是运行的程序:
*/
string LeftPart = "";//谓语动词的左边句
string RightPart = "";//谓语动词的右边句
//也可能找到一个动词(主谓宾句型),也可能找到两个动词(宾语补足语句型)
if (VerbBox1 != "" && VerbBox2 == "")//只找到1个动词,那就是谓语动词
{
FindVerb = VerbBox1;
}
else if (VerbBox1 != "" && VerbBox2 != "")//找到2个动词
{
FindVerb = VerbBox1;//位次在前面的动词是谓语动词
FindBuVerb = VerbBox2;//位次在后面的动词是宾语补足语动词
}
//谓语动词左边句(LeftPart)和谓语动词右边句(RightPart)是一个重要的转折,为以后的句子处理奠定了基础
LeftPart = dan.Substring(0, dan.IndexOf(FindVerb));
RightPart = dan.Substring(dan.IndexOf(FindVerb) + FindVerb.Length, dan.Length - (dan.IndexOf(FindVerb) + FindVerb.Length));
/*
例如句子(dan)是白色的猫吃黑色的鼠
find_word:吃
LeftPart:白色的猫
RightPart:黑色的鼠
UnityEngine.Debug.Log(find_verb);//谓语动词
UnityEngine.Debug.Log(LeftPart);//谓语动词的左边句
UnityEngine.Debug.Log(RightPart);//谓语动词的右边句
*/
/*
省略主语有两种情况:一种是主动语态省略主语,例如“跳过去”,全句指“你跳过去”。另一种是被动语态省略主语,例如“张三被打了”,没说谁打了张三,这里张三是宾语。如果说“李四打了张三”,李四就是主语。
被动语态的标志是“被”字,如果没有“被”字,而且省略了主语,就是主动语态省略主语的情况,那么这种情况下,主语应该填什么呢?例如“过来”,一般指“你过来”,但“走吧”一般指“我们走吧”。所以程序要根据具体的动词来判断省略的主语应该填什么。但是动词太多,每个动词都要设置省略的主语判断,太麻烦。所以省略主语,按最通常情况,就默认填“你”字,作为主语。如果主语是“我们”而不是“你”字,就不该省略主语。
被动语态应该还原为主动语态去理解,但被动语态往往没有主语,那么默认主语应该填什么呢?毕竟不知道主语,那就填“事物”这个词作为主语。
程序分析句子时,被动语态的主语位置的词,是宾语。例如“李四被打了”,李四在谓语动词左边句,程序会把李四当成主语,但在被动语态句里,李四不是主语,所以有“被”字的时候,主语要挪动到宾语位置,然后在主语位置补充“事物”这个词,作为主语。
但是有些时候,被动语态的主语是说明了的,例如“李四被张三打了”就还原为主动语态“张三打了李四”,张三做主语,而不是填“事物”做主语。
简而言之,被动语态里,主语放到了宾语位置,宾语放到了主语位置,所以变为主动语态时,要把宾语挪回主语位置,主语挪回宾语位置。
如果被动语态有主语,例如“李四被张三打了”,那么主语(张三)位于“被”字与谓语动词之间。
那么谓语动词左边句中,又分为“被”字左边句和“被”字右边句,被字左边句里的名词是宾语,被字右边句里的名词是主语。
*/
yutai = "主动";//默认主动语态
if (SentenceType == "主谓宾" && dan.Contains("被"))//语句中包含“被”字
{
if (dan.Contains("被子") == false && dan.Contains("被褥") == false)//语句中包含“被”字,但不是“被子”这个名词,才能指被动语态的“被”字
{
yutai = "被动";//被动语态
}
else
{
yutai = "主动";//主动语态
}
}
else//语句中没有包含“被”字
{
yutai = "主动";//主动语态
}
//对谓语动词左边句(LeftPart)的处理
if (LeftPart != "")//谓语动词左边句有内容
{
if (yutai == "主动")//主动语态
{
//找名词(主语)和名词所有格
FindSubject = SearchNoun(LeftPart);//在谓语动词左边句找名词(主语)
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
SubjectSuoyouge = TempSuoyouge;//是主语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(主语的形容词)
SubjectAdj = SearchAdj(LeftPart);
//找数词
FindNum = "";
NumDanwei = "";
num_type = "";
SearchNum(LeftPart);
SubjectNum = FindNum + NumDanwei;
//找时间
SearchTime1(LeftPart);//找时间:文字形式,例如今天、星期一
SearchTime2(LeftPart);//找时间:年月日时分
}
else if (yutai == "被动")//被动语态
{
string bei = "被";
string BeiLeft = "";
string BeiRight = "";
//被字左边句
BeiLeft = LeftPart.Substring(0, LeftPart.IndexOf(bei));
if (BeiLeft != "")
{
FindObject = SearchNoun(BeiLeft);//被字左边句的名词是宾语
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
ObjectSuoyouge = TempSuoyouge;//是宾语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(宾语的形容词)
ObjectAdj = SearchAdj(BeiLeft);
//找数词
FindNum = "";
NumDanwei = "";
num_type = "";
SearchNum(BeiLeft);
ObjectNum = FindNum + NumDanwei;
}
//被字右边句
BeiRight = LeftPart.Substring(LeftPart.IndexOf(bei) + bei.Length, LeftPart.Length - (LeftPart.IndexOf(bei) + bei.Length));
if (BeiRight != "")
{
FindSubject = SearchNoun(BeiRight);//被字右边句的名词是主语
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
SubjectSuoyouge = TempSuoyouge;//是主语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(主语的形容词)
SubjectAdj = SearchAdj(BeiRight);
//找数词
FindNum = "";
NumDanwei = "";
num_type = "";
SearchNum(BeiRight);
SubjectNum = FindNum + NumDanwei;
}
//如果没有主语,就填补“事物”这个词作为主语,毕竟被动语态经常没有主语
if (FindSubject == "" || FindSubject == null)//主语为空或主语不存在
{
FindSubject = "事物";
}
}
}
//如果省略主语,则填补省略的主语
if (yutai == "主动")
{
if (FindSubject == "" || FindSubject == null)//主语为空或主语不存在
{
FindSubject = "你";//默认填补“你”字做主语
}
}
//对谓语动词右边句(RightPart)的处理
if (SentenceType == "双宾语")//双宾语句型
{
FindObject = SearchNoun(RightPart);//找名词
//谓语动词右边句里,没有第二个宾语名词,那就不是双宾语
//例如虽然有双宾语句的标志动词“教”字,但他教我数学,是双宾语句,而他教书,是主谓宾句型
if (NounBox2 == "")
{
SentenceType = "主谓宾";
}
else
{
ShowResult();//显示最终输出结果
}
}
if (SentenceType == "主谓宾")//主谓宾句型
{
if (RightPart != "")
{
if (yutai == "主动")
{
//找名词和名词所有格
FindObject = SearchNoun(RightPart);//在谓语动词右边句找名词(宾语)
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
ObjectSuoyouge = TempSuoyouge;//是宾语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(宾语的形容词)
ObjectAdj = SearchAdj(RightPart);
//找数词
FindNum = "";
NumDanwei = "";
num_type = "";
SearchNum(RightPart);
ObjectNum = FindNum + NumDanwei;
}
}
ShowResult();//显示最终输出结果
}
if (SentenceType == "宾语补足语")//宾语补足语句型
{
//谓语动词到宾语补足语动词之间的部分里的名词,是宾语名词
string temp = "";
//截取谓语动词FindVerb和宾语补足语动词FindBuVerb之间的部分
temp = dan.Substring(dan.IndexOf(FindVerb) + FindVerb.Length, dan.IndexOf(FindBuVerb) - (dan.IndexOf(FindVerb) + FindVerb.Length));
FindObject = SearchNoun(temp);//找名词
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
ObjectSuoyouge = TempSuoyouge;//是宾语的名词所有格
TempSuoyouge = "";//置空
}
//宾语补足语右边句的名词,是宾语补足语名词,而不是宾语名词
int WordLastChar = dan.IndexOf(FindBuVerb) + FindBuVerb.Length;//宾语补足语动词最后一个字符的位置
if (WordLastChar < dan.Length)//宾语补足语动词最后一个字符的位置没有到全句末尾,就是说宾语补足语动词后面还有内容,那就是宾语补足语名词
{
//截取宾语补足语动词右边的内容
FindBuNoun = dan.Substring(dan.IndexOf(FindBuVerb) + FindBuVerb.Length, dan.Length - (dan.IndexOf(FindBuVerb) + FindBuVerb.Length));
//以后再写找宾语补足语名词的名词所有格
}
ShowResult();//显示最终输出结果
}
/*
靠句子包含的词直接与词库的词对比,来找主语(名词)、谓语(动词)、宾语(名词),会有问题:
第一个问题:熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
所以创建一个函数:WordCover(覆盖)。
词语槽(NounBox)存放这些找到词,以实现覆盖和吸收。
第二个问题:熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
对于第二个问题的解决方法:
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
所以创建一个de函数。
第三个问题:“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 学 | r1 | 生 |
+----------+---------+--------------+
| 压 | l1 | 气 |
+----------+---------+--------------+
word_col:判断这个字是动词还是名词。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
所以创建一个VerbJudge函数。
*/
}
//找名词(也包括找名词所有格)
string SearchNoun(string PartSentence)
{
string jieguo = "不包含";//默认值是不包含
int m = noun.Length;//名词数组的长度,也就是有多少个名词
//for循环前,先把词语槽清空,因为for循环时,调用的函数WordCover要用词语槽,来完成词语的覆盖和吸收
NounBox1 = "";
NounBox2 = "";
NounBox3 = "";
NounBox4 = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和名词的包含关系
就是用句子和名词数组的名词,一一比对,来判断是否包含名词
n的值从0逐渐增长到名词数组的名词数量值,这样数组也就经历了所有名词
*/
if (PartSentence.Contains(noun[n]))//包含
{
jieguo = "包含";
if (de(PartSentence, noun[n]) == false)//找到的名词右边的第一个字符不是“的”字,才算是名词,否则是名词所有格
{
NounCover(noun[n]);
}
else//名词右边的第一个字是“的”字,就意味着是名词所有格
{
TempSuoyouge = noun[n];//找到的名词所有格
}
}
}
if (jieguo == "包含")//找到了名词
{
NounOrder();//名词排序
//名词要先排序,才能合并名词,否则“足球”和“学校”的顺序如果变成“学校”和“足球”,那就合并成“学校足球”这个词了,而不是“足球学校”
//如果双宾语句型进行名词合并,就可能会把间接宾语名词和直接宾语名词合并到一起,成为一个名词,就不对了
if (SentenceType != "双宾语")//不是双宾语句型
{
NounJoin();//名词合并,例如把“足球”和“学校”合并成“足球学校”这一个名词
}
else if (SentenceType == "双宾语")//是双宾语句型
{
//但是如果现在处理的是双宾语结构的谓语动词左边句,也就是处理主语,还是可以名词合并的
if (dan.IndexOf(NounBox1) < dan.IndexOf(FindVerb))
{
NounJoin();//名词合并
}
}
return NounBox1;
}
else
{
return "";
}
}
//名词之间的覆盖
void NounCover(string FindWord)
{
/*
熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
词语槽(NounBox)存放这些找到词,以实现覆盖和吸收。
做了4个词语槽(NounBox),为了以后适应复杂的句子,但简单的主谓宾句型,一个词语槽就够了。
*/
if (NounBox1 == "" && FindWord != "")//词语槽还是空的,说明这是找到的第一个词
{
NounBox1 = FindWord;//找到的第1个词,放入词语槽
FindWord = "";//置空,免得填到词语槽2了
}
else if (NounBox1 != "" && FindWord != "")//词语槽1已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox1))//覆盖:例如找到的词(FindWord)是熊猫,词语槽1(NounBox1)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox1 = FindWord;//词语槽1的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽2了
}
else if (NounBox1.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽1(NounBox1)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,不要这个词了,免得填到词语槽2了
}
}
if (NounBox2 == "" && FindWord != "")//词语槽2是空的,FindWord经过词语槽1,没有覆盖或吸收,说明FindWord和词语槽1的词无关,例如FindWord是竹子
{
NounBox2 = FindWord;//找到的第2个词,放入词语槽
FindWord = "";//置空,免得填到词语槽3了
}
else if (NounBox2 != "" && FindWord != "")//词语槽2已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox2))//覆盖:例如找到的词(FindWord)是熊猫,词语槽2(NounBox2)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox2 = FindWord;//词语槽2的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽3了
}
else if (NounBox2.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽2(NounBox2)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽3了
}
}
if (NounBox3 == "" && FindWord != "")//词语槽3是空的,FindWord经过词语槽2,没有覆盖或吸收,说明FindWord和词语槽2的词无关,例如FindWord是竹子
{
NounBox3 = FindWord;//找到的第3个词,放入词语槽
FindWord = "";//置空,免得填到词语槽4了
}
else if (NounBox3 != "" && FindWord != "")//词语槽3已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox3))//覆盖:例如找到的词(FindWord)是熊猫,词语槽3(NounBox3)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox3 = FindWord;//词语槽3的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽4了
}
else if (NounBox3.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽3(NounBox3)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽4了
}
}
if (NounBox4 == "" && FindWord != "")//词语槽4是空的,FindWord经过词语槽3,没有覆盖或吸收,说明FindWord和词语槽3的词无关,例如FindWord是竹子
{
NounBox4 = FindWord;//找到的第4个词,放入词语槽
FindWord = "";//置空
}
else if (NounBox4 != "" && FindWord != "")//词语槽4已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox4))//覆盖:例如找到的词(FindWord)是熊猫,词语槽4(NounBox4)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox4 = FindWord;//词语槽4的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空
}
else if (NounBox4.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽4(NounBox4)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空
}
}
/*
“足球”这个词,会找到三个名词:足、球、足球。
先找到第一个词:足,放入NounBox1。
再找到第二个词:球,放入NounBox2。
再找到第三个词:足球,会覆盖NounBox1的“足”字,但却无法覆盖NounBox2的球字。
因此程序做一些改进。
但如果幸运的:
先找到第一个词:足球,放入NounBox1。
再找到第二个词:足,被NounBox1“足球”这个词吸收,不会进入到NounBox2。
再找到第三个词:球,被NounBox1“足球”这个词吸收,也不会进入到NounBox2。
那么就不用执行下面这段程序了。
先找到那个词是不确定的,词库词语可能按笔画排序,也可能按首字母排序,就不知道先找到那个词了。
如果输入的是“皮球”这个词,而词库里没有“皮球”这个词,但有“皮”字和“球”字这两个词。
那么,NounBox1是“皮”字,NounBox2是“球”字,或NounBox1是“球”字,NounBox2是“皮”字,没有覆盖和吸收。
*/
if (NounBox1.Contains(NounBox2))//NounBox1包含了NounBox2,例如“足球”包含“球”字
{
NounBox2 = "";
if (NounBox3 != "")
{
NounBox2 = NounBox3;
NounBox3 = "";
}
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";
}
}
if (NounBox2.Contains(NounBox3))//NounBox2包含了NounBox3
{
NounBox3 = "";
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";
}
}
if (NounBox3.Contains(NounBox4))//NounBox3包含了NounBox4
{
NounBox4 = "";
}
}
//动词之间的覆盖
void VerbCover(string str,string FindWord)
{
if (VerbBox1 == "" && FindWord != "")//动词槽还是空的,说明这是找到的第一个词
{
VerbBox1 = FindWord;//找到的第1个词,放入动词槽
FindWord = "";//置空,免得填到动词槽2了
}
else if (VerbBox1 != "" && FindWord != "")//动词槽1已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox1))//覆盖:例如找到的词(FindWord)是敲打,动词槽1(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox1 = FindWord;//词语槽1的词:长词覆盖短词,例如“敲打”覆盖“打”
FindWord = "";//置空,免得填到动词槽2了
}
else if (VerbBox1.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽1(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,不要这个词了,免得填到动词槽2了
}
}
if (VerbBox2 == "" && FindWord != "")//动词槽2是空的,FindWord经过动词槽1,没有覆盖或吸收,说明FindWord和动词槽1的词无关,例如FindWord是喜欢
{
VerbBox2 = FindWord;//找到的第2个词,放入动词槽
FindWord = "";//置空,免得填到动词槽3了
}
else if (VerbBox2 != "" && FindWord != "")//动词槽2已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox2))//覆盖:例如找到的词(FindWord)是敲打,动词槽2(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox2 = FindWord;//词语槽2的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽3了
}
else if (VerbBox2.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽2(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,免得填到词语槽3了
}
}
if (VerbBox3 == "" && FindWord != "")//动词槽3是空的,FindWord经过动词槽1和2,没有覆盖或吸收,说明FindWord和动词槽1、2的词无关,例如FindWord是喜欢
{
VerbBox3 = FindWord;//找到的第3个词,放入词语槽
FindWord = "";//置空,免得填到词语槽4了
}
else if (VerbBox3 != "" && FindWord != "")//动词槽3已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox3))//覆盖:例如找到的词(FindWord)是敲打,动词槽3(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox3 = FindWord;//词语槽3的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽4了
}
else if (VerbBox3.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽3(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,免得填到词语槽4了
}
}
if (VerbBox4 == "" && FindWord != "")//动词槽4是空的,FindWord经过动词槽1、2、3,没有覆盖或吸收,说明FindWord和动词槽1、2、3的词无关,例如FindWord是喜欢
{
VerbBox4 = FindWord;//找到的第4个词,放入词语槽
FindWord = "";//置空
}
else if (VerbBox4 != "" && FindWord != "")//动词槽4已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox4))//覆盖:例如找到的词(FindWord)是敲打,动词槽4(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox4 = FindWord;//词语槽4的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空
}
else if (VerbBox4.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽4(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空
}
}
/*
“敲打”这个词,会找到三个动词:敲、打、敲打
先找到第一个词:敲,放入VerbBox1
再找到第二个词:打,放入VerbBox2
再找到第三个词:敲打,会覆盖VerbBox1的“敲”字,但却无法覆盖VerbBox2的“打”字
因此程序做一些改进。
*/
if (VerbBox1.Contains(VerbBox2))//VerbBox1包含了VerbBox2
{
VerbBox2 = "";
if (VerbBox3 != "")
{
VerbBox2 = VerbBox3;
VerbBox3 = "";
}
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";
}
}
if (VerbBox2.Contains(VerbBox3))//VerbBox2包含了VerbBox3
{
VerbBox3 = "";
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";
}
}
if (VerbBox3.Contains(VerbBox4))//VerbBox3包含了VerbBox4
{
VerbBox4 = "";
}
}
//名词后面是否包含“的”字
bool de(string str,string word)
{
/*
熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
UnityEngine.Debug.Log(res);//显示:的
以上注释掉的内容只是解释原理,下面是运行程序:
*/
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLastChar = str.IndexOf(word) + word.Length;
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
if (res == "的")
{
return true;
}
else
{
return false;
}
}
//判断一个字是动词还是名词
bool VerbJudge(string str,string word)
{
/*
“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 学 | r1 | 生 |
+----------+---------+--------------+
| 压 | l1 | 气 |
+----------+---------+--------------+
word_col:判断这个字是动词还是名词,也就是辨析字。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。
“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
不容易理解的一处:
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 吹 | l1 | 电 |
+----------+---------+--------------+
“吹”字本身做动词,但在“电吹风”这个词里做名词,但我不用把“电吹风”这个三个字都判断,我只要判断“电吹”两个字就可以了。
遇到单字动词的时候,先看这个字是否在词性辨析表里,
如果在,type_col要求是r1(right1,就是要辨析的字的右边1个字符),那就看句子中要辨析的字的右边1个字符是不是符合词性表中的字,
如果符合,要辨析的字就是名词,而不是动词了。
例如学生看书,这句话先找到了动词“学”,在词性辨析表里,“学”字的type_col是r1,content_col是“生”字,
那就在句子中,看“学”字右边的1个字符是不是“生”字,如果是,“学”字就不做动词,而做名词了。
一个要辨析的字,type_col有四种可能:r1、r2、l1、l2,也就是右边1个字,右边2个字,左边1个字,左边2个字,那就要会四个方法:
符合r1:找辨析字右边1个字符:res = str.Substring(str.IndexOf(word) + word.Length, 1);
符合r2:找辨析字右边2个字符:res = str.Substring(str.IndexOf(word) + word.Length, 2);
符合l1:找辨析字左边1个字符:res = str.Substring(str.IndexOf(word) - 1, 1);
符合l2:找辨析字左边2个字符:res = str.Substring(str.IndexOf(word) - 2, 1);
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
res = str.Substring(str.IndexOf(word) + word.Length, 1);//变化形式
}
UnityEngine.Debug.Log(res);//显示:的
//指定词语左边1个字符
res = str.Substring(index - 1, 1);
res = str.Substring(str.IndexOf(word) - 1, 1);//变化形式
UnityEngine.Debug.Log(res);//显示:吃
以上注释掉的内容,只是解释原理,下面是运行程序:
*/
string[] TypeCol = new string[100];//把词性辨析表的辨析字对应的type_col值填充此数组
string[] ContentCol = new string[100];//把词性辨析表的辨析字对应的content_col值填充此数组
string res = "";//截取的字符
bool shima = true;//默认判断是动词
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
//字符型变量要有引号,数字型变量不需要引号
//word是变量,动态的,不能直接放到sql语句里面
string sqlQuery = "select type_col,content_col from verb_judge where word_col = '" + word + "'";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充词性辨析数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
//查询了2列(type_col和content_col),所以返回的结果集有2列,分别用GetValue(0)和GetValue(1)
TypeCol[i] = dbReader.GetValue(0).ToString();//返回的结果集的第1列
ContentCol[i] = dbReader.GetValue(1).ToString();//返回的结果集的第2列
i++;//虽然定义数组长度为10,但i不一定填满了10
}
dbReader.Close();
dbConnection.Close();
if (i > 0)//在词性辨析表里找到内容了,否则i还是默认的0
{
for (int n = 0; n < i; n++)//遍历词性辨析表找到的各种结果
{
if (TypeCol[n] == "r1")//right1:右边1个字符
{
if (str.IndexOf(word) + word.Length + 1 <= str.Length)//要往右判断1个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 1);//截取动词右边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "r2")//right2:右边2个字符
{
if (str.IndexOf(word) + word.Length + 2 <= str.Length)//要往右判断2个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 2);//截取动词右边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l1")//left1:左边1个字符
{
if (str.IndexOf(word) - 1 >= 0)//要往左判断1个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 1, 1);//截取动词左边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l2")//left2:左边2个字符
{
if (str.IndexOf(word) - 2 >= 0)//要往左判断2个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 2, 2);//截取动词左边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
}
}
i = 0;
return shima;
}
//判断句型
string SentenceJudge()
{
/*
基本单句有六种句型:
只有性质状态(表语):真漂亮、对啊、太好了。句子里没有谓语动词,其余五种句型里,都有谓语动词。
主语(动作执行者)-谓语(动作):张三摔倒。
主语(动作执行者)-谓语(动作)-宾语(动作对象):猫吃鼠。
主语-谓语(是)-表语(表明主语的身份和性质状态):张三是老师,太阳是美丽的。
双宾语句型:主语(传输的人)-谓语(传输动作)-间接宾语(传输对象)-直接宾语(传输的事物):张三给李四苹果,张三教李四数学。
宾语补足语句型:主语-谓语(例如把、使、让)-宾语-宾语补足语(做什么):张三让李四跳舞,张三把房间弄脏了。
前面只说了主谓宾句型,还要处理其它句型。
双宾语句型:
双宾语句型的谓语动词后面有两个名词,例如张三给李四苹果,李四是间接宾语(名词),苹果是直接宾语(名词)。
但是有两个名词的就是双宾语句型吗?不是的。例如张三喜欢足球学校。谓语动词后面有两个名词:足球、学校,但显然足球学校是一个整体名词,也就是主谓宾句型,而不是双宾语句型。因此判断双宾语句型,还要看谓语动词是不是适合双宾语句型的。
双宾语句型的谓语动词主要是传输事物的动词:给、送给、教。
那么谓语动词是双宾语句型的动词(例如给、教),且谓语动词后面有两个名词(体现为谓语动词右边的语句处理时,名词槽NounBox有两个名词,NounBox1和NounBox2都有值),就可以判断为双宾语句型。
还有,像“足球学校”这样两个名词连在一起,就要合并成一个名词,作为主语或宾语。
仅从双宾语句型的标志动词“教”判断双宾语句型,不一定准确,例如“他教我数学”是双宾语句型,但“他教书”就不是双宾语句型,所以还要根据宾语名词的数量,来判断到底是不是双宾语句型,如果动词右边只有一个名词,例如“他教书”的“书”,句子就不是双宾语句型。所以通过谓语动词判断一个句子是双宾语句型后,根据找到的名词数量,例如只有一个宾语名词,那么就要把双宾语句型,修正回主谓宾句型。
名词次序:间接宾语在直接宾语之前,所以找到两个名词,次序在前面的那个名词,是间接宾语,次序在后面的那个名词是直接宾语。
宾语补足语句型:
和主谓宾句型不同,宾语补足语句型含有主谓宾句型的部分,但宾语后面还有个动作(动词),也就是宾语补足语。
因此看宾语后面是否还有动词,是判断宾语补足语句型的方法。
但是有两个动词就麻烦了,如何判断这个动词是谓语动词还是宾语补足语动词呢?那就需要先把所有动词找出来,如果是宾语补足语动词,那么这个动词在谓语动词的后面,如果是谓语动词,则在前面。
既然要存放多个动词进行判断,就要有动词槽(VerbBox)。
动词次序:谓语动词在宾语补足语动词之前,所以找到两个动词,词语次序在前面的是谓语动词,词语次序在后面的是宾语补足语动词。
宾语补足语动词后面还有个名词,宾语补足语动词和这个名词合并在一起,作为宾语补足语。例如他让我打扫教室。如果宾语补足语只是“打扫”,话就说不清楚了。但是有些宾语补足语,就只有动词,后面没有名词,例如“他让我跳舞”就只有“跳舞”这一个动词,“跳舞”这个词后面没有名词,因为“跳舞”是不及物动词。
双宾语句型和宾语补足语句型,都是由主谓宾句型拓展而成的。双宾语句型在主谓宾句型的基础上,多加了一个宾语。宾语补足语句型在主谓宾句型的基础上,多加了一个动词(宾语补足语)。所以先完成主谓宾句型,再根据是否有拓展,来判断是不是双宾语句型或宾语补足语句型。
在主谓宾句型的基础上,如果没有宾语,就是主谓句型。如果没有主语,就是省略主语,例如对一个人喊“过来”,这句话的全句显然是“你过来”。
*/
if (VerbBox1 == "")//没有动词
{
return "只有性质状态";//只有性质状态的句型
}
else if (VerbBox1 != "" && VerbBox2 == "")//有1个动词
{
if (VerbBox1 == "给" || VerbBox1 == "送" || VerbBox1 == "送给" || VerbBox1 == "教")//双宾语句型的常见动词(标志词)
{
return "双宾语";//双宾语句型
}
else
{
return "主谓宾";//主谓宾句型
}
}
else if (VerbBox1 != "" && VerbBox2 != "")//有2个动词
{
return "宾语补足语";//宾语补足语句型
}
else
{
return "其它";
}
}
//名词排序
void NounOrder()
{
if (NounBox1 != "" && NounBox2 != "")//招到了2个名词,放在NounBox1和NounBox2
{
string temp = "";//临时变量
if (dan.IndexOf(NounBox1) > dan.IndexOf(NounBox2))//如果NounBox1的名词在句子中的位置大于NounBox2的名词在句子中的位置
{
//交换位置,在句子中位置小的名词放前面,从而确保双宾语句型时,NounBox1放的是间接宾语,NounBox2放的是直接宾语,毕竟间接宾语在直接宾语前面
temp = NounBox1;
NounBox1 = NounBox2;
NounBox2 = temp;
}
FindJianObject = NounBox1;
FindZhiObject = NounBox2;
//间接宾语和直接宾语的名词所有格,之后再做
}
}
//名词结合成名词词组
void NounJoin()
{
/*
名词合并:例如“足球学校”这个词,会被当成两个名词“足球”和“学校”。但实际中,要把它们合并成一个组合名词,作为主语或宾语。
前面说了判断两个字符之间的内容,如果两个字符(词语)是连续的,那么这两个词语之间的内容为空。
示例:
//截取两个指定字符之间的全部字符
string str = "白色的猫嘲笑黑色的鼠";//全句
string res = "";//结果
string word1 = "的猫";
string word2 = "的鼠";
int Word1LastIndex = str.IndexOf(word1) + word1.Length;
int Word2StartIndex = str.IndexOf(word2);
res = str.Substring(Word1LastIndex, Word2StartIndex - Word1LastIndex);
res = str.Substring(str.IndexOf(word1) + word1.Length, str.IndexOf(word2) - (str.IndexOf(word1) + word1.Length));//展开形式
if (res == "")
{
UnityEngine.Debug.Log("连续");
}
else
{
UnityEngine.Debug.Log("不连续");
}
*/
string res;
//判断NounBox1和NounBox2的名词是否需要合并
if (NounBox1 != "" && NounBox2 != "")
{
res = "";
//判断NounBox1和NounBox2之间是否有内容,如果没内容(res为空),就说明NounBox1和NounBox2是连续的名词(中间没有字符间隔),需要合并
res = dan.Substring(dan.IndexOf(NounBox1) + NounBox1.Length, dan.IndexOf(NounBox2) - (dan.IndexOf(NounBox1) + NounBox1.Length));
if (res == "")
{
NounBox1 = NounBox1 + NounBox2;//名词合并
NounBox2 = "";//合并后,置空
if (NounBox3 != "")
{
NounBox2 = NounBox3;//填补置空的值,否则NounBox1有值,NounBox2为空,NounBox3又有值,就间隔了
NounBox3 = "";//合并后,置空
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";//合并后,置空
}
}
}
}
/*
//判断NounBox2和NounBox3的名词是否需要合并
if (NounBox2 != "" && NounBox3 != "")
{
res = "";
//判断NounBox2和NounBox3之间是否有内容,如果没内容(res为空),就说明NounBox2和NounBox3是连续的名词,需要合并
res = dan.Substring(dan.IndexOf(NounBox2) + NounBox2.Length, dan.IndexOf(NounBox3) - (dan.IndexOf(NounBox2) + NounBox2.Length));
if (res == "")
{
NounBox2 = NounBox2 + NounBox3;//名词合并
NounBox3 = "";//合并后,置空
if (NounBox4 != "")
{
NounBox3 = NounBox4;//填补置空的值
NounBox4 = "";//合并后,置空
}
}
}
//判断NounBox3和NounBox4的名词是否需要合并
if (NounBox3 != "" && NounBox4 != "")
{
res = "";
//判断NounBox3和NounBox4之间是否有内容,如果没内容(res为空),就说明NounBox3和NounBox4是连续的名词,需要合并
res = dan.Substring(dan.IndexOf(NounBox3) + NounBox3.Length, dan.IndexOf(NounBox4) - (dan.IndexOf(NounBox3) + NounBox3.Length));
if (res == "")
{
NounBox3 = NounBox3 + NounBox4;//名词合并
NounBox4 = "";//合并后,置空
}
}
*/
}
//动词排序
void VerbOrder()
{
/*
如果不排序会怎样?句子中找到的第一个动词,可能不是谓语动词,而是宾语补足语动词,以宾语补足语动词分割句子,就错了。
谓语动词和宾语补足语动词,先找到哪个,取决于这两个词,谁在动词表前面排序,而动词的排序是不可知的,或许按笔划排序,或者按首字母排序
*/
string temp = "";//临时变量
if (VerbBox1 != "" && VerbBox2 != "")//招到了个动词,放在VerbBox1和VerbBox2
{
if (dan.IndexOf(VerbBox1) > dan.IndexOf(VerbBox2))//如果VerbBox1的动词在句子中的位置大于VerbBox2的动词在句子中的位置
{
//交换位置,在句子中位置小动词的放前面,从而确保VerbBox1放的是谓语动词,而宾语补足语动词放到VerbBox2
temp = VerbBox1;
VerbBox1 = VerbBox2;
VerbBox2 = temp;
}
}
if (VerbBox3 != "")
{
if (dan.IndexOf(VerbBox1) > dan.IndexOf(VerbBox3))
{
temp = VerbBox1;
VerbBox1 = VerbBox3;
VerbBox3 = temp;
}
if (dan.IndexOf(VerbBox2) > dan.IndexOf(VerbBox3))
{
temp = VerbBox2;
VerbBox2 = VerbBox3;
VerbBox3 = temp;
}
}
FindVerb = VerbBox1;
}
//动词结合成动词词组
void VerbJoin()
{
//动词合并:例如“应该爱”是两个动词:情态动词“应该”和普通动词“爱”,应该合并成一个动词
string res;
//判断VerbBox1和VerbBox2的动词是否需要合并
if (VerbBox1 != "" && VerbBox2 != "")
{
res = "";
//判断VerbBox1和VerbBox2之间是否有内容,如果没内容(res为空),就说明VerbBox1和VerbBox2是连续的动词(中间没有字符间隔),需要合并
res = dan.Substring(dan.IndexOf(VerbBox1) + VerbBox1.Length, dan.IndexOf(VerbBox2) - (dan.IndexOf(VerbBox1) + VerbBox1.Length));
if (res == "")
{
VerbBox1 = VerbBox1 + VerbBox2;//名词合并
FindVerb = VerbBox1;
VerbBox2 = "";//合并后,置空
if (VerbBox3 != "")
{
VerbBox2 = VerbBox3;//填补置空的值,否则VerbBox1有值,VerbBox2为空,VerbBox3又有值,就间隔了
VerbBox3 = "";//合并后,置空
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";//合并后,置空
}
}
}
}
}
//谓语动词的发生概率
void VerbRateJudge()
{
/*
动词前面是否有否定词,也很重要。
例如“他爱猫”和“他不爱猫”,虽然谓语动词都是“爱”字,但前面加个“不”字,意义就相反了。所以看谓语动词前面是否有否定词,是很重要的事。
谓语动词前面的否定词,一般有不、不要、不可以、不应该、不能、别。
还有不确定肯定还是否定动词,例如“他不一定去”,“去”字是动词,但是动词前的“不一定”,并不像是“不”字那样对动词进行否定,而是对动词既不像是肯定,也不像是否定,而是不确定。
因此对每句话的谓语动词,都要加一个性质:肯定、否定、不确定。
但不确定,有时候偏向于肯定,例如“他可能去”。有时候不确定偏向于否定,例如“他不太可能去”以及“他或许不去”。
那么动词发生概率分为五种:肯定、偏向肯定、不确定、偏向否定、否定。
这其实就是在分析事情(谓语动词)发生的概率,这在概率分析上有用。
指定词语左边1个字符:str.Substring(str.IndexOf(word) - 1, 1);
指定词语左边1个字符:str.Substring(str.IndexOf(word) - 2, 1);
*/
VerbRate = "肯定";//默认值:肯定
string temp = "";//临时变量
//先判断谓语动词左边的1个字符,是否是否定词
temp = dan.Substring(dan.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不"))
{
VerbRate = "否定";
}
else if(temp.Contains("别"))
{
VerbRate = "否定";
}
//判断谓语动词左边的2个字符,是否是否定词
temp = dan.Substring(dan.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不要"))
{
VerbRate = "否定";
}
else if (temp.Contains("不能"))
{
VerbRate = "否定";
}
else if (temp.Contains("可能"))
{
VerbRate = "不确定";
}
else if (temp.Contains("或许"))
{
VerbRate = "不确定";
}
//判断谓语动词左边的3个字符,是否是否定词
temp = dan.Substring(dan.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不可以"))
{
VerbRate = "否定";
}
else if (temp.Contains("不应该"))
{
VerbRate = "否定";
}
}
//找形容词
string SearchAdj(string str)
{
string jieguo = "不包含";//默认值是不包含
int m = adj.Length;//形容词数组的长度,也就是有多少个形容词
string temp = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和形容词的包含关系
就是用句子和形容词数组的形容词,一一比对,来判断是否包含形容词
n的值从0逐渐增长到形容词数组的形容词数量值,这样数组也就经历了所有形容词
*/
if (str.Contains(adj[n]))//包含
{
jieguo = "包含";
temp = adj[n];
}
}
if (jieguo == "包含")//找到了形容词
{
return temp;
}
else
{
return "";
}
}
//找数词
void SearchNum(string str)
{
//先确定数词单位
int StrLength = str.Length;//全句长度
string temp = "";
string NumDanwei_type = "";//数字单位类型
string[] shuzu_danwei_mignci = new string[] { "个", "名", "位", "只", "头", "匹", "条", "棵", "朵", "片", "根", "座", "栋", "台", "部", "本", "块", "件", "盏", "把", "所", "辆", "艘", "架", "扇" };
string[] shuzu_danwei_jiliang = new string[] { "米", "厘米", "毫米", "分米", "公里", "里", "微米", "纳米", "克", "斤", "公斤", "吨", "毫克", "升" };
//字符串从右向左,每次读取一个字符进行处理
for (int n = StrLength; n > 0; n--)
{
temp = str.Substring(n - 1, 1);//每次截取的一个字符,例如“年”字
if (NumDanwei_type == "")
{
//名词单位数组
foreach (string m in shuzu_danwei_mignci)//判断这个截取的字符是否在名词数组中
{
if (temp == m)//截取的字符属于名词数组(shuzu_danwei_mignci)中的字符,例如“个”字属于名词数组
{
NumDanwei = m;
NumDanwei_type = "名词单位";
SearchNum2(str, NumDanwei, NumDanwei_type);
if (num_type == "汉字型数字")
{
FindNum = SearchNum3(FindNum);
}
break;
}
}
}
if (NumDanwei_type == "")
{
//计量数组
foreach (string m in shuzu_danwei_jiliang)//判断这个截取的字符是否在计量数组中
{
if (temp == m)//截取的字符属于计量数组(shuzu_danwei_jiliang)中的字符,例如“米”字属于计量数组
{
NumDanwei = m;
if (str.Contains("厘"))
{
NumDanwei = "厘" + NumDanwei;
}
else if (str.Contains("毫"))
{
NumDanwei = "毫" + NumDanwei;
}
else if (str.Contains("公"))
{
NumDanwei = "公" + NumDanwei;
}
NumDanwei_type = "计量单位";
SearchNum2(str, NumDanwei, NumDanwei_type);
if (num_type == "汉字型数字")
{
FindNum = SearchNum3(FindNum);
}
break;
}
}
}
}
/*
找数字的其它方法:正则表达式。
需要using System.Text.RegularExpressions;//正则表达式找出数字所需
replace函数把不是数字的部分变为空无,这样就只剩下数字部分。
string res = "";
res = Regex.Replace(str, @"[^0-9]+", "");
return res;
*/
}
void SearchNum2(string str, string temp, string NumDanwei_type)
{
//找数字
string[] shuzu_num = new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" };
string[] shuzu_num_cn = new string[] { "一", "二", "两", "三", "四", "五", "六", "七", "八", "九", "零", "十", "百", "千", "万" };
//数量单位字符左边的字符串
string WordLeft = str.Substring(0, str.IndexOf(temp));//例如“有6米”的“有6”
//找阿拉伯数字,例如1、2、3这类数字
//逐一处理该字符左边的每个字符
int WordleftLength = WordLeft.Length;//例如“有6”这个字符串的长度
string temp2 = "";
//从右向左,逐字截取
for (int j = WordleftLength; j > 0; j--)
{
temp2 = WordLeft.Substring(j - 1, 1);//每次截取的一个字符
//从右到左,遇到不是数字的时候,就退出循环
if (temp2 != "1" && temp2 != "2" && temp2 != "3" && temp2 != "4" && temp2 != "5" && temp2 != "6" && temp2 != "7" && temp2 != "8" && temp2 != "9" && temp2 != "0")
{
break;
}
foreach (string m2 in shuzu_num)//判断这个截取的字符是否在数字数组中
{
if (temp2 == m2)//截取的字符属于数字数组(shuzu_num)中的字符,例如“1”字属于数字数组
{
if (NumDanwei_type == "名词单位" || NumDanwei_type == "计量单位")
{
//现在找出来的都是数字,但是都是倒序,需要拼接在一起
if (FindNum == "")
{
FindNum = temp2;
}
else
{
FindNum = temp2 + FindNum;
}
num_type = "阿拉伯数字";
}
}
}
}
if (NumDanwei_type == "名词单位" || NumDanwei_type == "计量单位")
{
if (FindNum == "")//没有找到阿拉伯数字
{
//找汉字型数字,例如一、二、三
WordleftLength = WordLeft.Length;//例如“有6”这个字符串的长度
temp2 = "";
//从右向左,逐字截取
for (int j = WordleftLength; j > 0; j--)
{
temp2 = WordLeft.Substring(j - 1, 1);//每次截取的一个字符
foreach (string m2 in shuzu_num_cn)//判断这个截取的字符是否在数字数组中
{
if (temp2 == m2)//截取的字符属于数字数组(shuzu_num)中的字符,例如“1”字属于数字数组
{
//现在找出来的都是数字,但是都是倒序,需要拼接在一起
if (FindNum == "")
{
FindNum = temp2;
}
else
{
FindNum = temp2 + FindNum;
}
num_type = "汉字型数字";
}
}
}
}
}
}
string SearchNum3(string find_num)
{
//汉字型数字转化为阿拉伯数字,例如“二十”转化为“20”
//这个转化有时候不准确
int old = 1;
int result = 0;
string temp = "";
int temp_num = 0;
//old(上一位数字)需要初始化为1,不能初始化为0,也不能不赋值
//因为如果数字开始(从左到右)第一个字符就是翻倍数(例如十),那么翻倍的上一位数(old)不能默认0或NULL
//如果翻倍数没有上一位数,拿默认1当上一位数(old初始化为1),翻倍数乘以1,就等于翻倍数翻倍自身,这样才正确
for (int n = 1; n <= find_num.Length; n++)
{
temp = find_num.Substring(n - 1, 1);//每次截取的一个字符
switch (temp)
{
case "一":
temp_num = 1;
break;
case "二":
temp_num = 2;
break;
case "两":
temp_num = 2;
break;
case "三":
temp_num = 3;
break;
case "四":
temp_num = 4;
break;
case "五":
temp_num = 5;
break;
case "六":
temp_num = 6;
break;
case "七":
temp_num = 7;
break;
case "八":
temp_num = 8;
break;
case "九":
temp_num = 9;
break;
case "零":
temp_num = 0;
break;
case "十":
temp_num = 10;
break;
case "百":
temp_num = 100;
break;
case "千":
temp_num = 1000;
break;
case "万":
temp_num = 10000;
break;
default:
break;
}
if (temp_num != 10 && temp_num != 100 && temp_num != 1000 && temp_num != 10000)//不是翻倍字符(十、百、千、万),而是0到9的数字
{
old = temp_num;//把数字存起来,下一次循环时,被下一位翻倍数所翻倍
if (n == find_num.Length)//当i的长度等于总数字的长度,也就是到了最后一位数(个位数),不用翻倍了
{
result = result + temp_num;//个位数不用翻倍,直接加
}
}
else//不是0到9的数字字符,而是翻倍字符,就要翻倍
{
//翻倍对象是上一位数字,就是old里存的数字。因为这次循环走else路线,所以temp_num没有赋值给old,因此old里还是上一位的数字
result = result + (old * temp_num);//此时的temp_num是翻倍单位(十、百、千、万),不是0到9的数字,翻倍上一位数字(old)
}
}
if (result != 0)
{
find_num = result.ToString();
return find_num;
}
else
{
return "";
}
}
//找时间(文字形式)
void SearchTime1(string str)
{
string[] shuzu_danwei_time1 = new string[] { "今天", "明天", "后天", "昨天", "前天", "这个月", "下个月", "上个月", "今年", "明年", "去年" };
string[] shuzu_danwei_time2 = new string[] { "早晨", "上午", "中午", "下午", "傍晚", "晚上", "傍晚", "夜晚", "半夜", "黎明", "黄昏", "清晨" };
string[] shuzu_danwei_time3 = new string[] { "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日", "礼拜一", "礼拜二", "礼拜三", "礼拜四", "礼拜五", "礼拜六", "礼拜天" };
string[] shuzu_danwei_time4 = new string[] { "春天", "夏天", "秋天", "冬天", "春季", "夏季", "秋季", "冬季" };
string[] shuzu_danwei_time5 = new string[] { "元旦", "大年三十", "除夕", "春节", "大年初一", "大年初二", "大年初三", "正月十五", "寒假", "清明节", "五一节", "劳动节", "儿童节", "暑假", "中秋节", "国庆节", "圣诞节", "假期", "休息日" };
foreach (string m in shuzu_danwei_time1)
{
if (str.Contains(m))
{
FindTime2 = m;
}
}
foreach (string m in shuzu_danwei_time2)
{
if (str.Contains(m))
{
FindTime2 = m;
}
}
foreach (string m in shuzu_danwei_time3)
{
if (str.Contains(m))
{
FindTime2 = m;
}
}
foreach (string m in shuzu_danwei_time4)
{
if (str.Contains(m))
{
FindTime2 = m;
}
}
foreach (string m in shuzu_danwei_time5)
{
if (str.Contains(m))
{
FindTime2 = m;
}
}
}
//找时间(年月日时分,布置框架)
void SearchTime2(string str)
{
//找年月日时分
string TimeDanwei = "";
if (str.Contains("年"))
{
TimeDanwei = "年";
FindTime_year = SearchTime3(str, TimeDanwei);
}
if (str.Contains("月"))
{
TimeDanwei = "月";
FindTime_month = SearchTime3(str, TimeDanwei);
if (num_type == "汉字型数字")
{
FindTime_month = SearchNum3(FindTime_month);
}
}
if (str.Contains("日"))
{
TimeDanwei = "日";
FindTime_day = SearchTime3(str, TimeDanwei);
}
if (str.Contains("点"))
{
TimeDanwei = "点";
FindTime_day = SearchTime3(str, TimeDanwei);
}
if (str.Contains("分"))
{
TimeDanwei = "分";
FindTime_day = SearchTime3(str, TimeDanwei);
}
}
//找时间(年月日时分,具体找)
string SearchTime3(string str, string TimeDanwei)
{
//找数字
string num = "";
string[] shuzu_num = new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" };
string[] shuzu_num_cn = new string[] { "一", "二", "两", "三", "四", "五", "六", "七", "八", "九", "零", "十", "百", "千", "万" };
//数量单位字符左边的字符串
string WordLeft = str.Substring(0, str.IndexOf(TimeDanwei));
//找阿拉伯数字,例如1、2、3这类数字
//逐一处理该字符左边的每个字符
int WordleftLength = WordLeft.Length;//例如“有6”这个字符串的长度
string temp = "";
//从右向左,逐字截取
for (int j = WordleftLength; j > 0; j--)
{
temp = WordLeft.Substring(j - 1, 1);//每次截取的一个字符
//从右到左,遇到不是数字的时候,就退出循环
if (temp != "1" && temp != "2" && temp != "3" && temp != "4" && temp != "5" && temp != "6" && temp != "7" && temp != "8" && temp != "9" && temp != "0")
{
break;
}
foreach (string m in shuzu_num)//判断这个截取的字符是否在数字数组中
{
if (temp == m)//截取的字符属于数字数组(shuzu_num)中的字符,例如“1”字属于数字数组
{
//现在找出来的都是数字,但是都是倒序,需要拼接在一起
if (num == "")
{
num = temp;
}
else
{
num = temp + num;
}
num_type = "阿拉伯数字";
}
}
}
if (num == "")//没有找到阿拉伯数字
{
//找汉字型数字,例如一、二、三
WordleftLength = WordLeft.Length;//例如“有6”这个字符串的长度
temp = "";
//从右向左,逐字截取
for (int j = WordleftLength; j > 0; j--)
{
temp = WordLeft.Substring(j - 1, 1);//每次截取的一个字符
foreach (string m2 in shuzu_num_cn)//判断这个截取的字符是否在数字数组中
{
if (temp == m2)//截取的字符属于数字数组(shuzu_num)中的字符,例如“1”字属于数字数组
{
//现在找出来的都是数字,但是都是倒序,需要拼接在一起
if (num == "")
{
num = temp;
}
else
{
num = temp + num;
}
num_type = "汉字型数字";
}
}
}
}
if (num != "")
{
return num;
}
else
{
return "";
}
}
//显示最终输出结果
void ShowResult()
{
UnityEngine.Debug.Log("第" + dan_num + "句:" + danju[dan_num-1]);
UnityEngine.Debug.Log("句型:" + SentenceType);
if (SentenceType == "主谓宾")//主谓宾句型
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("宾语:" + FindObject);
UnityEngine.Debug.Log("语态:" + yutai);
}
else if (SentenceType == "双宾语")
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("间接宾语:" + FindJianObject);
UnityEngine.Debug.Log("直接宾语:" + FindZhiObject);
}
else if (SentenceType == "宾语补足语")
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("宾语:" + FindObject);
UnityEngine.Debug.Log("宾语补足语动词:" + FindBuVerb);
UnityEngine.Debug.Log("宾语补足语名词:" + FindBuNoun);
}
else if (SentenceType == "只有性质状态")
{
UnityEngine.Debug.Log("只有性质状态:" + dan);
}
UnityEngine.Debug.Log("动词发生概率:" + VerbRate);
//显示名词所有格
if (SubjectSuoyouge != "")
{
UnityEngine.Debug.Log("主语的名词所有格:" + SubjectSuoyouge);
}
if (ObjectSuoyouge != "")
{
UnityEngine.Debug.Log("宾语的名词所有格:" + ObjectSuoyouge);
}
/*
if (JianSuoyouge != "")
{
UnityEngine.Debug.Log("间接宾语的名词所有格:" + JianSuoyouge);
}
if (ZhiSuoyouge != "")
{
UnityEngine.Debug.Log("直接宾语的名词所有格:" + ZhiSuoyouge);
}
if (BuSuoyouge != "")
{
UnityEngine.Debug.Log("宾语补足语的名词所有格:" + BuSuoyouge);
}
*/
//显示形容词
if (SubjectAdj != "")
{
UnityEngine.Debug.Log("主语的形容词:" + SubjectAdj);
}
if (ObjectAdj != "")
{
UnityEngine.Debug.Log("宾语的形容词:" + ObjectAdj);
}
/*
if (JianAdj != "")
{
UnityEngine.Debug.Log("间接宾语的形容词:" + JianAdj);
}
if (ZhiAdj != "")
{
UnityEngine.Debug.Log("直接宾语的形容词:" + ZhiAdj);
}
if (BuAdj != "")
{
UnityEngine.Debug.Log("宾语补足语的形容词:" + BuAdj);
}
*/
//显示数词
if (SubjectNum != "")
{
UnityEngine.Debug.Log("主语的数词:" + SubjectNum);
}
if (ObjectNum != "")
{
UnityEngine.Debug.Log("宾语的数词:" + ObjectNum);
}
/*
if (JianNum != "")
{
UnityEngine.Debug.Log("间接宾语的形容词:" + JianNum);
}
if (ZhiNum != "")
{
UnityEngine.Debug.Log("直接宾语的形容词:" + ZhiNum);
}
if (BuNum != "")
{
UnityEngine.Debug.Log("宾语补足语的形容词:" + BuNum);
}
*/
//显示时间:
/*
string FindTime_year = "";//要找的时间:年
string FindTime_month = "";//要找的时间:月
string FindTime_day = "";//要找的时间:日
string FindTime_hour = "";//要找的时间:小时
string FindTime_minute = "";//要找的时间:分钟
string FindTime2 = "";//要找的时间(文字形式,例如下午、星期一)
*/
if (FindTime_year != "")
{
UnityEngine.Debug.Log("年:" + FindTime_year);
}
if (FindTime_month != "")
{
UnityEngine.Debug.Log("月:" + FindTime_month);
}
if (FindTime_day != "")
{
UnityEngine.Debug.Log("日:" + FindTime_day);
}
if (FindTime_hour != "")
{
UnityEngine.Debug.Log("时(几点):" + FindTime_hour);
}
if (FindTime_minute != "")
{
UnityEngine.Debug.Log("分(几分):" + FindTime_minute);
}
if (FindTime2 != "")
{
UnityEngine.Debug.Log("时间:" + FindTime2);
}
//tmpText.text = mes;
//清空变量
FindSubject = "";
FindVerb = "";
FindObject = "";
FindBuVerb = "";
FindBuNoun = "";
FindJianObject = "";
FindZhiObject = "";
yutai = "";
SubjectSuoyouge = "";
ObjectSuoyouge = "";
/*
JianSuoyouge = "";
ZhiSuoyouge = "";
BuSuoyouge = "";
*/
}
}
第六章
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;//Canvas框显示输入框和输出框所需
using TMPro;//Text Mesh Pro文字控件所需
using Mono.Data.Sqlite;//连接sqlite数据库所需
public class sqlitecon : MonoBehaviour
{
//输入和输出
public TMP_InputField inputField;//输入框对象(把层级面板上的输入框控件拖动到此框里)
string shuru = "";//输入框内容
//public TMP_Text tmpText;//输出框对象(把层级面板上的输出框控件拖动到此框里)
//string mes;//输出框内容
//词库
string[] noun = new string[7128];//名词数组,名词数量7128(数据库增加名词后,此处也要修改,以免造成溢出)
string[] verb = new string[5886];//动词数组,动词数量5886(数据库增加动词后,此处也要修改,以免造成溢出)
string[] adj = new string[1777];//形容词数组,形容词数量1777(数据库增加形容词后,此处也要修改,以免造成溢出)
//按标点符号分割句子
string dan = "";//按标点符号分割出的基本单句
string[] danju = new string[100];//单句的数组储存
int dan_num = 1;//第几个单句
//单句里,谓语动词分割出的左右句
string LeftPart = "";//谓语动词的左边句
string RightPart = "";//谓语动词的右边句
//基本单句的语法结构
string FindSubject = "";//主语
string FindVerb = "";//谓语动词
string FindObject = "";//宾语
string FindBuVerb = "";//宾语补足语的动词
string FindBuNoun = "";//宾语补足语的名词
string FindJianObject = "";//间接宾语
string FindZhiObject = "";//直接宾语
//名词所有格(例如张三的猫,张三就是名词所有格,“的”字就不写了)
string SubjectSuoyouge = "";//主语的名词所有格
string ObjectSuoyouge = "";//宾语的名词所有格
string JianSuoyouge = "";//间接宾语的名词所有格
string ZhiSuoyouge = "";//直接宾语的名词所有格
string BuSuoyouge = "";//宾语补足语的名词所有格
string TempSuoyouge = "";//临时存放名词所有格
//形容词
string SubjectAdj = "";//主语的形容词
string ObjectAdj = "";//宾语的形容词
string JianAdj = "";//间接宾语的形容词
string ZhiAdj = "";//直接宾语的形容词
string BuAdj = "";//宾语补足语的形容词
//数词
string SubjectNum = "";//主语的数词
string ObjectNum = "";//宾语的数词
string JianNum = "";//间接宾语的数词
string ZhiNum = "";//直接宾语的数词
string BuNum = "";//宾语补足语的数词
//语法结构的相关描述
string SentenceType = "";//句型
string yutai = "";//语态:主动语态还是被动语态
string VerbRate = "";//动词发生概率:肯定、偏向肯定、不确定、偏向否定、否定
//名词槽(名词之间相互覆盖时用)
string NounBox1 = "";//名词槽1
string NounBox2 = "";//名词槽2
string NounBox3 = "";//名词槽3
string NounBox4 = "";//名词槽4
//动词槽(动词之间相互覆盖时用)
string VerbBox1 = "";//动词槽1
string VerbBox2 = "";//动词槽2
string VerbBox3 = "";//动词槽3
string VerbBox4 = "";//动词槽4
//数词和时间
string FindNum = "";//要找的数词的数字
string NumDanwei = "";//数词单位
string FindTime_year = "";//要找的时间:年
string FindTime_month = "";//要找的时间:月
string FindTime_day = "";//要找的时间:日
string FindTime_hour = "";//要找的时间:小时
string FindTime_minute = "";//要找的时间:分钟
string FindTime2 = "";//要找的时间(文字形式,例如下午、星期一)
string num_type = "";//数字类型:阿拉伯数字(例如1、2、3)还是汉字型数字(例如一、二、三)
//地点
string didian = "";
// Start is called before the first frame update
void Start()
{
ciku();//填充词库
inputField.onEndEdit.AddListener(OnInputEndEdit);//输入完成后,对回车键的响应(按回车键发送)
}
// Update is called once per frame
void Update()
{
}
//填充词库(数据库的词库填充到数组中)
void ciku()
{
//生成游戏后,需要把sqlite数据库复制到生成的游戏的文件夹里,那个文件夹自动生成的这个数据库是0kb,无效的,需要重新复制过去
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
int i = 0;
//填充名词数组
//第一步:sql指令
string sqlQuery = "SELECT word_col FROM noun";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充名词数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
while (dbReader.Read())
{
noun[i] = dbReader.GetValue(0).ToString();//GetValue(0)表示结果集的第一列,因为只查询了一列,所以返回的结果集就一列
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示名词数量
//填充动词数组
//第一步:sql指令
sqlQuery = "SELECT word_col FROM verb";//sql指令
//第二步:执行指令
//dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充动词数组
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
verb[i] = dbReader.GetValue(0).ToString();
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示动词数量
//填充形容词数组
//第一步:sql指令
sqlQuery = "SELECT word_col FROM adj";//sql指令
//第二步:执行指令
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充动词数组
dbReader = dbCommand.ExecuteReader();
i = 0;
while (dbReader.Read())
{
adj[i] = dbReader.GetValue(0).ToString();
i++;
}
dbReader.Close();
//UnityEngine.Debug.Log(i);//显示形容词数量
dbConnection.Close();//关闭数据库连接
}
//输入完成后,按回车键发送,便开始执行此函数
void OnInputEndEdit(string value)
{
shuru = inputField.text;//输入框的内容
SplitSay();//按标点符号,分割输入内容
}
//按标点符号,分割输入内容,分割成基本单句
void SplitSay()
{
/*
输入的内容可能是一大段内容,需要分割成一个个基本单句,从而逐一处理。
基本单句就是主语-谓语-宾语,或主语-谓语-间接宾语-直接宾语,或主语-谓语-宾语-宾语补足语,这类语法上的基本单句。
那就需要按逗号分割句子,按句号分割句子,才能拆分成一个个这样的基本单句。
按逗号分割句子:
string str = "早晨,中午,下午";
string word = ",";
string[] shuzu = str.Split(word);//按word指定的分隔符,分割字符串,并存入数组中
foreach (string part in shuzu)
{
UnityEngine.Debug.Log(part);
}
按逗号和句号分割句子:
string str = "早晨,中午。下午,傍晚";
string word = ",";
string[] shuzu = str.Split(word);//按word指定的分隔符(逗号),分割字符串,并存入数组中
foreach (string part in shuzu)
{
string word2 = "。";
string[] shuzu2 = part.Split(word2);//按word2指定的分隔符(句号),分割字符串,并存入数组中
foreach (string part2 in shuzu2)
{
UnityEngine.Debug.Log(part2);
}
}
计算标点符号的数量:
string str = "早晨,中午。下午,傍晚";
string temp = "";
int dou = 0;//逗号数量
int ju = 0;//句号数量
int str_length = str.Length;//句子长度
temp = str.Replace(",", "");//把逗号替换为空无,就是去掉逗号
int str_length_delete_dou = temp.Length;//去掉逗号后,句子的长度
dou = str_length - str_length_delete_dou;//两者相减,就是逗号的数量
temp = str.Replace("。", "");//把句号替换为空无,就是去掉句号
int str_length_delete_ju = temp.Length;//去掉句号后,句子的长度
ju = str_length - str_length_delete_ju;//两者相减,就是句号的数量
以上注释掉的内容,只是解释说明,下面才是运行的程序:
*/
//计算标点符号的数量
string temp = "";
int dou = 0;//逗号数量
int ju = 0;//句号数量
int str_length = shuru.Length;//句子长度
//计算逗号的数量
temp = shuru.Replace(",", "");//把逗号替换为空无,就是去掉逗号
int str_length_delete_dou = temp.Length;//去掉逗号后,句子的长度
dou = str_length - str_length_delete_dou;//两者相减,就是逗号的数量
//计算句号的数量
temp = shuru.Replace("。", "");//把句号替换为空无,就是去掉句号
int str_length_delete_ju = temp.Length;//去掉句号后,句子的长度
ju = str_length - str_length_delete_ju;//两者相减,就是句号的数量
//按标点符号分割句子
if (dou > 0 || ju > 0)//逗号大于0或句号大于0,就是输入的内容有标点符号
{
string word = ",";//分割符:中文的逗号
string[] shuzu = shuru.Split(word);//按word指定的分隔符(逗号),分割字符串,并存入数组中
foreach (string part in shuzu)//逐个处理
{
string word2 = "。";//分割符:中文的句号
string[] shuzu2 = part.Split(word2);//按word2指定的分隔符(句号),分割字符串,并存入数组中
foreach (string part2 in shuzu2)//逐个处理
{
dan = part2;//基本单句已经分割出来了,在part2里,并赋值给dan(基本单句)
danju[dan_num - 1] = part2;//数组从0开始计算,而danju从1开始计算,所以换算上要减1
ClearData();//清除上次的变量数据
//UnityEngine.Debug.Log("单句:" + dan);
SearchVerb(dan);//找谓语动词(这是单句处理的第一步)
dan = "";
dan_num++;
}
}
}
else//输入的内容,没有标点符号
{
if (shuru != "")//有输入的内容
{
dan = shuru;//输入的内容就是一个基本单句
danju[0] = shuru;
SearchVerb(dan);//找谓语动词
dan = "";
}
}
//后面分析一句话,记着用变量dan,不要再用变量shuru了,因为变量shuru是整段话(可以是多句话组成),变量dan才是分割出的单句
}
//清除上次循环(基本单句处理)的变量数据
void ClearData()
{
FindSubject = "";//主语
FindVerb = "";//谓语动词
FindObject = "";//宾语
FindBuVerb = "";//宾语补足语的动词
FindBuNoun = "";//宾语补足语的名词
FindJianObject = "";//间接宾语
FindZhiObject = "";//直接宾语
SubjectSuoyouge = "";//主语的名词所有格
ObjectSuoyouge = "";//宾语的名词所有格
TempSuoyouge = "";//临时存放名词所有格
SubjectAdj = "";//主语的形容词
ObjectAdj = "";//宾语的形容词
SubjectNum = "";//主语的数词
ObjectNum = "";//宾语的数词
SentenceType = "";//句型
yutai = "";//语态:主动语态还是被动语态
VerbRate = "";//动词发生概率:肯定、偏向肯定、不确定、偏向否定、否定
NounBox1 = "";//名词槽1
NounBox2 = "";//名词槽2
NounBox3 = "";//名词槽3
NounBox4 = "";//名词槽4
VerbBox1 = "";//动词槽1
VerbBox2 = "";//动词槽2
VerbBox3 = "";//动词槽3
VerbBox4 = "";//动词槽4
FindNum = "";
NumDanwei = "";
num_type = "";
}
//找谓语动词
void SearchVerb(string str)
{
string jieguo = "不包含";//默认值是不包含动词
int m = verb.Length;//动词数组的长度,也就是有多少个动词
LeftPart = "";
RightPart = "";
VerbBox1 = "";
VerbBox2 = "";
VerbBox3 = "";
VerbBox4 = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和动词的包含关系
就是用句子和动词数组的动词,一一比对,来判断是否包含动词
n的值从0逐渐增长到动词数组的动词数量值,这样数组也就经历了所有动词
*/
if (str.Contains(verb[n]))//包含动词
{
if (VerbJudge(str, verb[n]) == true)//是动词,不是名词
{
jieguo = "包含";
FindVerb = verb[n];//找到了动词
VerbCover(str, verb[n]);//把动词放入动词槽里,看看有几个动词
VerbOrder();//动词排序
VerbJoin();//动词结合
}
}
}
if (jieguo == "包含")//包含动词
{
VerbRateJudge();//动词发生概率:肯定、偏向肯定、不确定、偏向否定、否定
SentenceType = SentenceJudge();//判断句型(仅从动词情况来判断句型,还不是完全清楚的判断,之后还需进一步判断)
SplitSentence();//以谓语动词为分割符,来分割句子
}
}
//以谓语动词为分割符,来分割句子
void SplitSentence()
{
/*
对于主谓宾句型,先找出动词,然后以动词为分割符号,分割句子。动词左边分割出的句子的名词就是主语,动词右边分割出的句子的名词就是宾语
先举个例子简单说明一下字符串分割的基本原理:
string str = "白色的猫嘲笑黑色的鼠";//全句
string word = "嘲笑";//指定词
string res = "";//结果
int chang = 0;//全句长度
int index = 0;//指定词语的起始位置
int LastIndex = 0;//指定词语最后一个字符在全句中的位置
int jie = 0;//临时变量
//计算全句长度
chang = str.Length;//显示字符个数,从1开始计算
//计算指定字符在全句中的位置
index = str.IndexOf(word) + 1;//默认从0计算,例如第2个字符,显示为1,而不是2。为了调整为1开始计算,所以加1
//计算指定词语最后一个字符在全句中的位置
LastIndex = str.IndexOf(word) + word.Length;
//截取第3个字符右边的1个字符
Substring(开始位置, 向右截取长度),从1开始计算,不是0
res = str.Substring(3,1); //从第3个字符开始,向右截取1个字符
//截取指定字符右边的全部字符
jie = chang - LastIndex;//截取长度 = 全句长度 - 指定词语最后一个字符的位置长度
res = str.Substring(LastIndex, jie);
res = str.Substring(str.IndexOf(word) + word.Length, str.Length - (str.IndexOf(word) + word.Length));//展开形式
//截取指定字符左边的全部字符
res = str.Substring(0, index);//从句子开始的0位置,截取长度是指定字符的位置长度
res = str.Substring(0, str.IndexOf(word));//变化形式
//截取两个指定字符之间的全部字符
string word1 = "的猫";
string word2 = "的鼠";
int Word1LastIndex = str.IndexOf(word1) + word1.Length;
int Word2StartIndex = str.IndexOf(word2);
res = str.Substring(Word1LastIndex, Word2StartIndex - Word1LastIndex);
res = str.Substring(str.IndexOf(word1) + word1.Length, str.IndexOf(word2) - (str.IndexOf(word1) + word1.Length));//展开形式
//数组形式截取字符
//前面定义了:str = "白色的猫吃黑色的鼠"; word = "吃";
string[] shuzu = str.Split(word);//按指定分割符分割字符串,并存入数组中
UnityEngine.Debug.Log(shuzu[0]);//显示:白色的猫
UnityEngine.Debug.Log(shuzu[1]);//显示:黑色的鼠
//或逐一显示数组全部
foreach (string part in shuzu)
{
UnityEngine.Debug.Log(part);
}
以上注释掉的内容,只是解释原理,下面是运行的程序:
*/
//也可能找到一个动词(主谓宾句型),也可能找到两个动词(宾语补足语句型)
if (VerbBox1 != "" && VerbBox2 == "")//只找到1个动词,那就是谓语动词
{
FindVerb = VerbBox1;
}
else if (VerbBox1 != "" && VerbBox2 != "")//找到2个动词
{
FindVerb = VerbBox1;//位次在前面的动词是谓语动词
FindBuVerb = VerbBox2;//位次在后面的动词是宾语补足语动词
}
//谓语动词左边句(LeftPart)和谓语动词右边句(RightPart)是一个重要的转折,为以后的句子处理奠定了基础
LeftPart = dan.Substring(0, dan.IndexOf(FindVerb));
RightPart = dan.Substring(dan.IndexOf(FindVerb) + FindVerb.Length, dan.Length - (dan.IndexOf(FindVerb) + FindVerb.Length));
/*
例如句子(dan)是白色的猫吃黑色的鼠
find_word:吃
LeftPart:白色的猫
RightPart:黑色的鼠
UnityEngine.Debug.Log(find_verb);//谓语动词
UnityEngine.Debug.Log(LeftPart);//谓语动词的左边句
UnityEngine.Debug.Log(RightPart);//谓语动词的右边句
*/
/*
省略主语有两种情况:一种是主动语态省略主语,例如“跳过去”,全句指“你跳过去”。另一种是被动语态省略主语,例如“张三被打了”,没说谁打了张三,这里张三是宾语。如果说“李四打了张三”,李四就是主语。
被动语态的标志是“被”字,如果没有“被”字,而且省略了主语,就是主动语态省略主语的情况,那么这种情况下,主语应该填什么呢?例如“过来”,一般指“你过来”,但“走吧”一般指“我们走吧”。所以程序要根据具体的动词来判断省略的主语应该填什么。但是动词太多,每个动词都要设置省略的主语判断,太麻烦。所以省略主语,按最通常情况,就默认填“你”字,作为主语。如果主语是“我们”而不是“你”字,就不该省略主语。
被动语态应该还原为主动语态去理解,但被动语态往往没有主语,那么默认主语应该填什么呢?毕竟不知道主语,那就填“事物”这个词作为主语。
程序分析句子时,被动语态的主语位置的词,是宾语。例如“李四被打了”,李四在谓语动词左边句,程序会把李四当成主语,但在被动语态句里,李四不是主语,所以有“被”字的时候,主语要挪动到宾语位置,然后在主语位置补充“事物”这个词,作为主语。
但是有些时候,被动语态的主语是说明了的,例如“李四被张三打了”就还原为主动语态“张三打了李四”,张三做主语,而不是填“事物”做主语。
简而言之,被动语态里,主语放到了宾语位置,宾语放到了主语位置,所以变为主动语态时,要把宾语挪回主语位置,主语挪回宾语位置。
如果被动语态有主语,例如“李四被张三打了”,那么主语(张三)位于“被”字与谓语动词之间。
那么谓语动词左边句中,又分为“被”字左边句和“被”字右边句,被字左边句里的名词是宾语,被字右边句里的名词是主语。
*/
yutai = "主动";//默认主动语态
if (SentenceType == "主谓宾" && dan.Contains("被"))//语句中包含“被”字
{
if (dan.Contains("被子") == false && dan.Contains("被褥") == false)//语句中包含“被”字,但不是“被子”这个名词,才能指被动语态的“被”字
{
yutai = "被动";//被动语态
}
else
{
yutai = "主动";//主动语态
}
}
else//语句中没有包含“被”字
{
yutai = "主动";//主动语态
}
//对谓语动词左边句(LeftPart)的处理
if (LeftPart != "")//谓语动词左边句有内容
{
if (yutai == "主动")//主动语态
{
//找名词(主语)和名词所有格
FindSubject = SearchNoun(LeftPart);//在谓语动词左边句找名词(主语)
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
SubjectSuoyouge = TempSuoyouge;//是主语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(主语的形容词)
SubjectAdj = SearchAdj(LeftPart);
//找数词
FindNum = "";
NumDanwei = "";
num_type = "";
SearchNum(LeftPart);
SubjectNum = FindNum + NumDanwei;
//找时间
SearchTime1(LeftPart);//找时间:文字形式,例如今天、星期一
SearchTime2(LeftPart);//找时间:年月日时分
}
else if (yutai == "被动")//被动语态
{
string bei = "被";
string BeiLeft = "";
string BeiRight = "";
//被字左边句
BeiLeft = LeftPart.Substring(0, LeftPart.IndexOf(bei));
if (BeiLeft != "")
{
FindObject = SearchNoun(BeiLeft);//被字左边句的名词是宾语
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
ObjectSuoyouge = TempSuoyouge;//是宾语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(宾语的形容词)
ObjectAdj = SearchAdj(BeiLeft);
//找数词
FindNum = "";
NumDanwei = "";
num_type = "";
SearchNum(BeiLeft);
ObjectNum = FindNum + NumDanwei;
//找时间
SearchTime1(BeiLeft);//找时间:文字形式,例如今天、星期一
SearchTime2(BeiLeft);//找时间:年月日时分
}
//被字右边句
BeiRight = LeftPart.Substring(LeftPart.IndexOf(bei) + bei.Length, LeftPart.Length - (LeftPart.IndexOf(bei) + bei.Length));
if (BeiRight != "")
{
FindSubject = SearchNoun(BeiRight);//被字右边句的名词是主语
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
SubjectSuoyouge = TempSuoyouge;//是主语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(主语的形容词)
SubjectAdj = SearchAdj(BeiRight);
//找数词
FindNum = "";
NumDanwei = "";
num_type = "";
SearchNum(BeiRight);
SubjectNum = FindNum + NumDanwei;
}
//如果没有主语,就填补“事物”这个词作为主语,毕竟被动语态经常没有主语
if (FindSubject == "" || FindSubject == null)//主语为空或主语不存在
{
FindSubject = "事物";
}
}
}
//如果省略主语,则填补省略的主语
if (yutai == "主动")
{
if (FindSubject == "" || FindSubject == null)//主语为空或主语不存在
{
FindSubject = "你";//默认填补“你”字做主语
}
}
//对谓语动词右边句(RightPart)的处理
if (SentenceType == "双宾语")//双宾语句型
{
FindObject = SearchNoun(RightPart);//找名词
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
ZhiSuoyouge = TempSuoyouge;//是直接宾语的名词所有格(暂且这样设置)
TempSuoyouge = "";//置空
}
//谓语动词右边句里,没有第二个宾语名词,那就不是双宾语
//例如虽然有双宾语句的标志动词“教”字,但他教我数学,是双宾语句,而他教书,是主谓宾句型
if (NounBox2 == "")
{
SentenceType = "主谓宾";
ZhiSuoyouge = "";//既然不作为双宾语句型了,原来的直接宾语所有格也就要清空了
}
else
{
//直接宾语的定语(形容词、数词、名词所有格),在间接宾语和直接宾语之间
//例如张三给李四红色的苹果,李四是间接宾语,苹果是直接宾语,红色的是形容词
if (FindJianObject != "" && FindZhiObject != "")//间接宾语和直接宾语不为空
{
string BewteenPart = "";
BewteenPart = RightPart.Substring(RightPart.IndexOf(FindJianObject) + FindJianObject.Length, RightPart.IndexOf(FindZhiObject) - (RightPart.IndexOf(FindJianObject) + FindJianObject.Length));
if (BewteenPart != "")
{
//找形容词
ZhiAdj = SearchAdj(BewteenPart);
//找数词
FindNum = "";
NumDanwei = "";
num_type = "";
SearchNum(BewteenPart);
ZhiNum = FindNum + NumDanwei;
}
}
//间接宾语的定语在谓语动词和间接宾语之间,对于谓语动词右边句,也就是句子开始到间接宾语之间
//例如张三给美丽的李四苹果,李四是间接宾语,美丽的是形容词
if (FindJianObject != "")//间接宾语不为空
{
string PartLeft = "";
PartLeft = RightPart.Substring(0, RightPart.IndexOf(FindJianObject));
if (PartLeft != "")
{
//找形容词
JianAdj = SearchAdj(PartLeft);
//找数词
FindNum = "";
NumDanwei = "";
num_type = "";
SearchNum(PartLeft);
JianNum = FindNum + NumDanwei;
}
}
ShowResult();//显示最终输出结果
}
}
if (SentenceType == "主谓宾")//主谓宾句型
{
if (RightPart != "")
{
if (yutai == "主动")
{
//找名词和名词所有格
FindObject = SearchNoun(RightPart);//在谓语动词右边句找名词(宾语)
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
ObjectSuoyouge = TempSuoyouge;//是宾语的名词所有格
TempSuoyouge = "";//置空
}
//找形容词(宾语的形容词)
ObjectAdj = SearchAdj(RightPart);
//找数词
FindNum = "";
NumDanwei = "";
num_type = "";
SearchNum(RightPart);
ObjectNum = FindNum + NumDanwei;
}
}
ShowResult();//显示最终输出结果
}
if (SentenceType == "宾语补足语")//宾语补足语句型
{
//谓语动词到宾语补足语动词之间的部分里的名词,是宾语名词
string temp = "";
//截取谓语动词FindVerb和宾语补足语动词FindBuVerb之间的部分
temp = dan.Substring(dan.IndexOf(FindVerb) + FindVerb.Length, dan.IndexOf(FindBuVerb) - (dan.IndexOf(FindVerb) + FindVerb.Length));
FindObject = SearchNoun(temp);//找名词
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
ObjectSuoyouge = TempSuoyouge;//是宾语的名词所有格
TempSuoyouge = "";//置空
}
//宾语补足语右边句的名词,是宾语补足语名词,而不是宾语名词
int WordLastChar = dan.IndexOf(FindBuVerb) + FindBuVerb.Length;//宾语补足语动词最后一个字符的位置
if (WordLastChar < dan.Length)//宾语补足语动词最后一个字符的位置没有到全句末尾,就是说宾语补足语动词后面还有内容,那就是宾语补足语名词
{
//截取宾语补足语动词右边的内容
string BuRight = dan.Substring(dan.IndexOf(FindBuVerb) + FindBuVerb.Length, dan.Length - (dan.IndexOf(FindBuVerb) + FindBuVerb.Length));
FindBuNoun = SearchNoun(BuRight);//找名词(上次写错了,写成temp了,那就把宾语也当要找的名词了)
if (TempSuoyouge != "")//找名词时,顺便还找到了名词所有格
{
BuSuoyouge = TempSuoyouge;//是宾语补足语的名词所有格
TempSuoyouge = "";//置空
}
//宾语补足语名词的定语(形容词、数词、名词所有格)在宾语补足语动词的右边(BuRight)
//例如张三让李四打扫蓝色的房间,打扫是宾语补足语的动词,房间是宾语补足语的名词,蓝色的是形容词
//找形容词
BuAdj = SearchAdj(BuRight);
//找数词
FindNum = "";
NumDanwei = "";
num_type = "";
SearchNum(BuRight);
BuNum = FindNum + NumDanwei;
}
ShowResult();//显示最终输出结果
}
/*
靠句子包含的词直接与词库的词对比,来找主语(名词)、谓语(动词)、宾语(名词),会有问题:
第一个问题:熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
所以创建一个函数:WordCover(覆盖)。
词语槽(NounBox)存放这些找到词,以实现覆盖和吸收。
第二个问题:熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
对于第二个问题的解决方法:
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
所以创建一个de函数。
第三个问题:“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 学 | r1 | 生 |
+----------+---------+--------------+
| 压 | l1 | 气 |
+----------+---------+--------------+
word_col:判断这个字是动词还是名词。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
所以创建一个VerbJudge函数。
*/
}
//找名词(也包括找名词所有格)
string SearchNoun(string PartSentence)
{
string jieguo = "不包含";//默认值是不包含
int m = noun.Length;//名词数组的长度,也就是有多少个名词
//for循环前,先把词语槽清空,因为for循环时,调用的函数WordCover要用词语槽,来完成词语的覆盖和吸收
NounBox1 = "";
NounBox2 = "";
NounBox3 = "";
NounBox4 = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和名词的包含关系
就是用句子和名词数组的名词,一一比对,来判断是否包含名词
n的值从0逐渐增长到名词数组的名词数量值,这样数组也就经历了所有名词
*/
if (PartSentence.Contains(noun[n]))//句子包含名词
{
jieguo = "包含";
//找到的名词不是名词所有格,也不是地点,才是主语或宾语的名词
if (de(PartSentence, noun[n]) == false)//找到的名词右边的第一个字符不是“的”字,才算是名词,否则是名词所有格
{
if (difang(PartSentence, noun[n]) == false)//找到的名词左边的第一个字符,不是地点动词
{
NounCover(noun[n]);
}
else//名词左边第一个字是“在”或“到”或“去”或“来”,那么这个名词就是地点,而不是作为主语名词
{
didian = noun[n];//找到的地点
}
}
else//名词右边的第一个字是“的”字,就意味着是名词所有格
{
TempSuoyouge = noun[n];//找到的名词所有格
}
}
}
if (jieguo == "包含")//找到了名词
{
NounOrder();//名词排序
//名词要先排序,才能合并名词,否则“足球”和“学校”的顺序如果变成“学校”和“足球”,那就合并成“学校足球”这个词了,而不是“足球学校”
//如果双宾语句型进行名词合并,就可能会把间接宾语名词和直接宾语名词合并到一起,成为一个名词,就不对了
if (SentenceType != "双宾语")//不是双宾语句型
{
NounJoin();//名词合并,例如把“足球”和“学校”合并成“足球学校”这一个名词
}
else if (SentenceType == "双宾语")//是双宾语句型
{
//但是如果现在处理的是双宾语结构的谓语动词左边句,也就是处理主语,还是可以名词合并的
if (dan.IndexOf(NounBox1) < dan.IndexOf(FindVerb))
{
NounJoin();//名词合并
}
}
return NounBox1;
}
else
{
return "";
}
}
//名词之间的覆盖
void NounCover(string FindWord)
{
/*
熊猫吃竹子,这句话里你感觉有感觉有两个名词:熊猫、竹子,但是电脑会找出四个名词:熊猫、熊、猫、竹子。
对于第一个问题的解决方法:
新找到的长词(熊猫)覆盖已找到的短词(熊、猫)。
已找到的长词(熊猫)吸收新找到的短词(熊、猫)。
词语槽(NounBox)存放这些找到词,以实现覆盖和吸收。
做了4个词语槽(NounBox),为了以后适应复杂的句子,但简单的主谓宾句型,一个词语槽就够了。
*/
if (NounBox1 == "" && FindWord != "")//词语槽还是空的,说明这是找到的第一个词
{
NounBox1 = FindWord;//找到的第1个词,放入词语槽
FindWord = "";//置空,免得填到词语槽2了
}
else if (NounBox1 != "" && FindWord != "")//词语槽1已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox1))//覆盖:例如找到的词(FindWord)是熊猫,词语槽1(NounBox1)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox1 = FindWord;//词语槽1的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽2了
}
else if (NounBox1.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽1(NounBox1)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,不要这个词了,免得填到词语槽2了
}
}
if (NounBox2 == "" && FindWord != "")//词语槽2是空的,FindWord经过词语槽1,没有覆盖或吸收,说明FindWord和词语槽1的词无关,例如FindWord是竹子
{
NounBox2 = FindWord;//找到的第2个词,放入词语槽
FindWord = "";//置空,免得填到词语槽3了
}
else if (NounBox2 != "" && FindWord != "")//词语槽2已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox2))//覆盖:例如找到的词(FindWord)是熊猫,词语槽2(NounBox2)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox2 = FindWord;//词语槽2的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽3了
}
else if (NounBox2.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽2(NounBox2)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽3了
}
}
if (NounBox3 == "" && FindWord != "")//词语槽3是空的,FindWord经过词语槽2,没有覆盖或吸收,说明FindWord和词语槽2的词无关,例如FindWord是竹子
{
NounBox3 = FindWord;//找到的第3个词,放入词语槽
FindWord = "";//置空,免得填到词语槽4了
}
else if (NounBox3 != "" && FindWord != "")//词语槽3已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox3))//覆盖:例如找到的词(FindWord)是熊猫,词语槽3(NounBox3)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox3 = FindWord;//词语槽3的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽4了
}
else if (NounBox3.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽3(NounBox3)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空,免得填到词语槽4了
}
}
if (NounBox4 == "" && FindWord != "")//词语槽4是空的,FindWord经过词语槽3,没有覆盖或吸收,说明FindWord和词语槽3的词无关,例如FindWord是竹子
{
NounBox4 = FindWord;//找到的第4个词,放入词语槽
FindWord = "";//置空
}
else if (NounBox4 != "" && FindWord != "")//词语槽4已经有找到的词了,例如已经放入熊或猫或熊猫,而现在又找到词熊或猫或熊猫
{
if (FindWord.Contains(NounBox4))//覆盖:例如找到的词(FindWord)是熊猫,词语槽4(NounBox4)的词是熊,“熊猫”包含(Contain)“熊”字
{
NounBox4 = FindWord;//词语槽4的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空
}
else if (NounBox4.Contains(FindWord))//吸收:例如找到的词(FindWord)是熊,词语槽4(NounBox4)的词是熊猫,“熊”字属于“熊猫”
{
FindWord = "";//置空
}
}
/*
“足球”这个词,会找到三个名词:足、球、足球。
先找到第一个词:足,放入NounBox1。
再找到第二个词:球,放入NounBox2。
再找到第三个词:足球,会覆盖NounBox1的“足”字,但却无法覆盖NounBox2的球字。
因此程序做一些改进。
但如果幸运的:
先找到第一个词:足球,放入NounBox1。
再找到第二个词:足,被NounBox1“足球”这个词吸收,不会进入到NounBox2。
再找到第三个词:球,被NounBox1“足球”这个词吸收,也不会进入到NounBox2。
那么就不用执行下面这段程序了。
先找到那个词是不确定的,词库词语可能按笔画排序,也可能按首字母排序,就不知道先找到那个词了。
如果输入的是“皮球”这个词,而词库里没有“皮球”这个词,但有“皮”字和“球”字这两个词。
那么,NounBox1是“皮”字,NounBox2是“球”字,或NounBox1是“球”字,NounBox2是“皮”字,没有覆盖和吸收。
*/
if (NounBox1.Contains(NounBox2))//NounBox1包含了NounBox2,例如“足球”包含“球”字
{
NounBox2 = "";
if (NounBox3 != "")
{
NounBox2 = NounBox3;
NounBox3 = "";
}
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";
}
}
if (NounBox2.Contains(NounBox3))//NounBox2包含了NounBox3
{
NounBox3 = "";
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";
}
}
if (NounBox3.Contains(NounBox4))//NounBox3包含了NounBox4
{
NounBox4 = "";
}
}
//动词之间的覆盖
void VerbCover(string str,string FindWord)
{
if (VerbBox1 == "" && FindWord != "")//动词槽还是空的,说明这是找到的第一个词
{
VerbBox1 = FindWord;//找到的第1个词,放入动词槽
FindWord = "";//置空,免得填到动词槽2了
}
else if (VerbBox1 != "" && FindWord != "")//动词槽1已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox1))//覆盖:例如找到的词(FindWord)是敲打,动词槽1(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox1 = FindWord;//词语槽1的词:长词覆盖短词,例如“敲打”覆盖“打”
FindWord = "";//置空,免得填到动词槽2了
}
else if (VerbBox1.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽1(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,不要这个词了,免得填到动词槽2了
}
}
if (VerbBox2 == "" && FindWord != "")//动词槽2是空的,FindWord经过动词槽1,没有覆盖或吸收,说明FindWord和动词槽1的词无关,例如FindWord是喜欢
{
VerbBox2 = FindWord;//找到的第2个词,放入动词槽
FindWord = "";//置空,免得填到动词槽3了
}
else if (VerbBox2 != "" && FindWord != "")//动词槽2已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox2))//覆盖:例如找到的词(FindWord)是敲打,动词槽2(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox2 = FindWord;//词语槽2的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽3了
}
else if (VerbBox2.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽2(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,免得填到词语槽3了
}
}
if (VerbBox3 == "" && FindWord != "")//动词槽3是空的,FindWord经过动词槽1和2,没有覆盖或吸收,说明FindWord和动词槽1、2的词无关,例如FindWord是喜欢
{
VerbBox3 = FindWord;//找到的第3个词,放入词语槽
FindWord = "";//置空,免得填到词语槽4了
}
else if (VerbBox3 != "" && FindWord != "")//动词槽3已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox3))//覆盖:例如找到的词(FindWord)是敲打,动词槽3(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox3 = FindWord;//词语槽3的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空,免得填到词语槽4了
}
else if (VerbBox3.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽3(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空,免得填到词语槽4了
}
}
if (VerbBox4 == "" && FindWord != "")//动词槽4是空的,FindWord经过动词槽1、2、3,没有覆盖或吸收,说明FindWord和动词槽1、2、3的词无关,例如FindWord是喜欢
{
VerbBox4 = FindWord;//找到的第4个词,放入词语槽
FindWord = "";//置空
}
else if (VerbBox4 != "" && FindWord != "")//动词槽4已经有找到的词了,例如已经放入敲打或敲或打,而现在又找到词敲打或敲或打
{
if (FindWord.Contains(VerbBox4))//覆盖:例如找到的词(FindWord)是敲打,动词槽4(VerbBox1)的词是打,“敲打”包含(Contain)“打”字
{
VerbBox4 = FindWord;//词语槽4的词:长词覆盖短词,例如“熊猫”覆盖“熊”
FindWord = "";//置空
}
else if (VerbBox4.Contains(FindWord))//吸收:例如找到的词(FindWord)是打,动词槽4(VerbBox1)的词是敲打,“打”字属于“敲打”
{
FindWord = "";//置空
}
}
/*
“敲打”这个词,会找到三个动词:敲、打、敲打
先找到第一个词:敲,放入VerbBox1
再找到第二个词:打,放入VerbBox2
再找到第三个词:敲打,会覆盖VerbBox1的“敲”字,但却无法覆盖VerbBox2的“打”字
因此程序做一些改进。
*/
if (VerbBox1.Contains(VerbBox2))//VerbBox1包含了VerbBox2
{
VerbBox2 = "";
if (VerbBox3 != "")
{
VerbBox2 = VerbBox3;
VerbBox3 = "";
}
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";
}
}
if (VerbBox2.Contains(VerbBox3))//VerbBox2包含了VerbBox3
{
VerbBox3 = "";
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";
}
}
if (VerbBox3.Contains(VerbBox4))//VerbBox3包含了VerbBox4
{
VerbBox4 = "";
}
}
//名词后面是否包含“的”字
bool de(string str,string word)
{
/*
熊猫喜欢森林的竹子,这句话动词右边句有两个名词,竹子是宾语,而森林不是宾语,因为森林后边有个“的”字,是名词所有格。
找到的名词右边的第一个字符,看它是不是“的”字,如果是“的”字,那么这个名词就不是宾语,找主语也是同理。
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
UnityEngine.Debug.Log(res);//显示:的
以上注释掉的内容只是解释原理,下面是运行程序:
*/
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLastChar = str.IndexOf(word) + word.Length;
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
}
if (res == "的")
{
return true;
}
else
{
return false;
}
}
//判断一个字是动词还是名词
bool VerbJudge(string str,string word)
{
/*
“学”字是动词,但是在“学生”这个词里,“学”字就变成名词了,还当动词理解,就会错。
对于第三个问题的解决方法:
建立词性辨析表:verb_judge
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 学 | r1 | 生 |
+----------+---------+--------------+
| 压 | l1 | 气 |
+----------+---------+--------------+
word_col:判断这个字是动词还是名词,也就是辨析字。
type_col:r1表示right1,就是指content_col的字是word_col的那个字的右边那1个字,也就是“学生”的“生”字。
l1表示left1,就是指content_col的字是word_col的那个字的左边那1个字,也就是“气压”的“气”字。
“压”是本身是动词,但左边那个字是“气”字时,“压”字就变为名词了,也就是名词“气压”的“压”。
l是字母L的小写,不是数字1。l1是两个不同的字符。
不容易理解的一处:
+----------+----------+-------------+
| word_col | type_col | content_col |
+----------+---------+--------------+
| 吹 | l1 | 电 |
+----------+---------+--------------+
“吹”字本身做动词,但在“电吹风”这个词里做名词,但我不用把“电吹风”这个三个字都判断,我只要判断“电吹”两个字就可以了。
遇到单字动词的时候,先看这个字是否在词性辨析表里,
如果在,type_col要求是r1(right1,就是要辨析的字的右边1个字符),那就看句子中要辨析的字的右边1个字符是不是符合词性表中的字,
如果符合,要辨析的字就是名词,而不是动词了。
例如学生看书,这句话先找到了动词“学”,在词性辨析表里,“学”字的type_col是r1,content_col是“生”字,
那就在句子中,看“学”字右边的1个字符是不是“生”字,如果是,“学”字就不做动词,而做名词了。
一个要辨析的字,type_col有四种可能:r1、r2、l1、l2,也就是右边1个字,右边2个字,左边1个字,左边2个字,那就要会四个方法:
符合r1:找辨析字右边1个字符:res = str.Substring(str.IndexOf(word) + word.Length, 1);
符合r2:找辨析字右边2个字符:res = str.Substring(str.IndexOf(word) + word.Length, 2);
符合l1:找辨析字左边1个字符:res = str.Substring(str.IndexOf(word) - 1, 1);
符合l2:找辨析字左边2个字符:res = str.Substring(str.IndexOf(word) - 2, 1);
截取指定字符右边1个字符的基本原理:
string str = "白色的猫吃黑色的鼠";//全句
string word = "黑色";//指定词
int index = 0;//指定词的位置(索引)
int WordLength = 0;//词语长度
int WordLastChar = 0;//词语最后一个字符的位置
string res = "";//结果
WordLength = word.Length;
index = str.IndexOf(word);
//指定词语右边1个字符
WordLastChar = index + WordLength;
WordLastChar = str.IndexOf(word) + word.Length;//变化形式
if (WordLastChar < str.Length)
{
res = str.Substring(WordLastChar, 1);
res = str.Substring(str.IndexOf(word) + word.Length, 1);//变化形式
}
UnityEngine.Debug.Log(res);//显示:的
//指定词语左边1个字符
res = str.Substring(index - 1, 1);
res = str.Substring(str.IndexOf(word) - 1, 1);//变化形式
UnityEngine.Debug.Log(res);//显示:吃
以上注释掉的内容,只是解释原理,下面是运行程序:
*/
string[] TypeCol = new string[100];//把词性辨析表的辨析字对应的type_col值填充此数组
string[] ContentCol = new string[100];//把词性辨析表的辨析字对应的content_col值填充此数组
string res = "";//截取的字符
bool shima = true;//默认判断是动词
//连接数据库
string connectionString = @"Data Source=garden.db;Version=3;";
SqliteConnection dbConnection;
dbConnection = new SqliteConnection(connectionString);
dbConnection.Open();
//填充名词数组
//第一步:sql指令
//字符型变量要有引号,数字型变量不需要引号
//word是变量,动态的,不能直接放到sql语句里面
string sqlQuery = "select type_col,content_col from verb_judge where word_col = '" + word + "'";
//第二步:执行指令
SqliteCommand dbCommand;
dbCommand = dbConnection.CreateCommand();
dbCommand.CommandText = sqlQuery;
dbCommand.ExecuteNonQuery();
//第三步:填充词性辨析数组
SqliteDataReader dbReader;
dbReader = dbCommand.ExecuteReader();
int i = 0;
while (dbReader.Read())
{
//查询了2列(type_col和content_col),所以返回的结果集有2列,分别用GetValue(0)和GetValue(1)
TypeCol[i] = dbReader.GetValue(0).ToString();//返回的结果集的第1列
ContentCol[i] = dbReader.GetValue(1).ToString();//返回的结果集的第2列
i++;//虽然定义数组长度为10,但i不一定填满了10
}
dbReader.Close();
dbConnection.Close();
if (i > 0)//在词性辨析表里找到内容了,否则i还是默认的0
{
for (int n = 0; n < i; n++)//遍历词性辨析表找到的各种结果
{
if (TypeCol[n] == "r1")//right1:右边1个字符
{
if (str.IndexOf(word) + word.Length + 1 <= str.Length)//要往右判断1个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 1);//截取动词右边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "r2")//right2:右边2个字符
{
if (str.IndexOf(word) + word.Length + 2 <= str.Length)//要往右判断2个字符,但不能超出数组界限
{
res = str.Substring(str.IndexOf(word) + word.Length, 2);//截取动词右边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l1")//left1:左边1个字符
{
if (str.IndexOf(word) - 1 >= 0)//要往左判断1个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 1, 1);//截取动词左边1个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
else if (TypeCol[n] == "l2")//left2:左边2个字符
{
if (str.IndexOf(word) - 2 >= 0)//要往左判断2个字符,但不能低于数组界限0
{
res = str.Substring(str.IndexOf(word) - 2, 2);//截取动词左边2个字符
if (res == ContentCol[n])//截取的字符符合词性辨析表对应的字符
{
shima = false;//不是动词
}
}
}
}
}
i = 0;
return shima;
}
//判断句型
string SentenceJudge()
{
/*
基本单句有六种句型:
只有性质状态(表语):真漂亮、对啊、太好了。句子里没有谓语动词,其余五种句型里,都有谓语动词。
主语(动作执行者)-谓语(动作):张三摔倒。
主语(动作执行者)-谓语(动作)-宾语(动作对象):猫吃鼠。
主语-谓语(是)-表语(表明主语的身份和性质状态):张三是老师,太阳是美丽的。
双宾语句型:主语(传输的人)-谓语(传输动作)-间接宾语(传输对象)-直接宾语(传输的事物):张三给李四苹果,张三教李四数学。
宾语补足语句型:主语-谓语(例如把、使、让)-宾语-宾语补足语(做什么):张三让李四跳舞,张三把房间弄脏了。
前面只说了主谓宾句型,还要处理其它句型。
双宾语句型:
双宾语句型的谓语动词后面有两个名词,例如张三给李四苹果,李四是间接宾语(名词),苹果是直接宾语(名词)。
但是有两个名词的就是双宾语句型吗?不是的。例如张三喜欢足球学校。谓语动词后面有两个名词:足球、学校,但显然足球学校是一个整体名词,也就是主谓宾句型,而不是双宾语句型。因此判断双宾语句型,还要看谓语动词是不是适合双宾语句型的。
双宾语句型的谓语动词主要是传输事物的动词:给、送给、教。
那么谓语动词是双宾语句型的动词(例如给、教),且谓语动词后面有两个名词(体现为谓语动词右边的语句处理时,名词槽NounBox有两个名词,NounBox1和NounBox2都有值),就可以判断为双宾语句型。
还有,像“足球学校”这样两个名词连在一起,就要合并成一个名词,作为主语或宾语。
仅从双宾语句型的标志动词“教”判断双宾语句型,不一定准确,例如“他教我数学”是双宾语句型,但“他教书”就不是双宾语句型,所以还要根据宾语名词的数量,来判断到底是不是双宾语句型,如果动词右边只有一个名词,例如“他教书”的“书”,句子就不是双宾语句型。所以通过谓语动词判断一个句子是双宾语句型后,根据找到的名词数量,例如只有一个宾语名词,那么就要把双宾语句型,修正回主谓宾句型。
名词次序:间接宾语在直接宾语之前,所以找到两个名词,次序在前面的那个名词,是间接宾语,次序在后面的那个名词是直接宾语。
宾语补足语句型:
和主谓宾句型不同,宾语补足语句型含有主谓宾句型的部分,但宾语后面还有个动作(动词),也就是宾语补足语。
因此看宾语后面是否还有动词,是判断宾语补足语句型的方法。
但是有两个动词就麻烦了,如何判断这个动词是谓语动词还是宾语补足语动词呢?那就需要先把所有动词找出来,如果是宾语补足语动词,那么这个动词在谓语动词的后面,如果是谓语动词,则在前面。
既然要存放多个动词进行判断,就要有动词槽(VerbBox)。
动词次序:谓语动词在宾语补足语动词之前,所以找到两个动词,词语次序在前面的是谓语动词,词语次序在后面的是宾语补足语动词。
宾语补足语动词后面还有个名词,宾语补足语动词和这个名词合并在一起,作为宾语补足语。例如他让我打扫教室。如果宾语补足语只是“打扫”,话就说不清楚了。但是有些宾语补足语,就只有动词,后面没有名词,例如“他让我跳舞”就只有“跳舞”这一个动词,“跳舞”这个词后面没有名词,因为“跳舞”是不及物动词。
双宾语句型和宾语补足语句型,都是由主谓宾句型拓展而成的。双宾语句型在主谓宾句型的基础上,多加了一个宾语。宾语补足语句型在主谓宾句型的基础上,多加了一个动词(宾语补足语)。所以先完成主谓宾句型,再根据是否有拓展,来判断是不是双宾语句型或宾语补足语句型。
在主谓宾句型的基础上,如果没有宾语,就是主谓句型。如果没有主语,就是省略主语,例如对一个人喊“过来”,这句话的全句显然是“你过来”。
*/
if (VerbBox1 == "")//没有动词
{
return "只有性质状态";//只有性质状态的句型
}
else if (VerbBox1 != "" && VerbBox2 == "")//有1个动词
{
if (VerbBox1 == "给" || VerbBox1 == "送" || VerbBox1 == "送给" || VerbBox1 == "教")//双宾语句型的常见动词(标志词)
{
return "双宾语";//双宾语句型
}
else
{
return "主谓宾";//主谓宾句型
}
}
else if (VerbBox1 != "" && VerbBox2 != "")//有2个动词
{
return "宾语补足语";//宾语补足语句型
}
else
{
return "其它";
}
}
//名词排序
void NounOrder()
{
if (NounBox1 != "" && NounBox2 != "")//招到了2个名词,放在NounBox1和NounBox2
{
string temp = "";//临时变量
if (dan.IndexOf(NounBox1) > dan.IndexOf(NounBox2))//如果NounBox1的名词在句子中的位置大于NounBox2的名词在句子中的位置
{
//交换位置,在句子中位置小的名词放前面,从而确保双宾语句型时,NounBox1放的是间接宾语,NounBox2放的是直接宾语,毕竟间接宾语在直接宾语前面
temp = NounBox1;
NounBox1 = NounBox2;
NounBox2 = temp;
}
FindJianObject = NounBox1;
FindZhiObject = NounBox2;
//间接宾语和直接宾语的名词所有格,之后再做
}
}
//名词结合成名词词组
void NounJoin()
{
/*
名词合并:例如“足球学校”这个词,会被当成两个名词“足球”和“学校”。但实际中,要把它们合并成一个组合名词,作为主语或宾语。
前面说了判断两个字符之间的内容,如果两个字符(词语)是连续的,那么这两个词语之间的内容为空。
示例:
//截取两个指定字符之间的全部字符
string str = "白色的猫嘲笑黑色的鼠";//全句
string res = "";//结果
string word1 = "的猫";
string word2 = "的鼠";
int Word1LastIndex = str.IndexOf(word1) + word1.Length;
int Word2StartIndex = str.IndexOf(word2);
res = str.Substring(Word1LastIndex, Word2StartIndex - Word1LastIndex);
res = str.Substring(str.IndexOf(word1) + word1.Length, str.IndexOf(word2) - (str.IndexOf(word1) + word1.Length));//展开形式
if (res == "")
{
UnityEngine.Debug.Log("连续");
}
else
{
UnityEngine.Debug.Log("不连续");
}
*/
string res;
//判断NounBox1和NounBox2的名词是否需要合并
if (NounBox1 != "" && NounBox2 != "")
{
res = "";
//判断NounBox1和NounBox2之间是否有内容,如果没内容(res为空),就说明NounBox1和NounBox2是连续的名词(中间没有字符间隔),需要合并
res = dan.Substring(dan.IndexOf(NounBox1) + NounBox1.Length, dan.IndexOf(NounBox2) - (dan.IndexOf(NounBox1) + NounBox1.Length));
if (res == "")
{
NounBox1 = NounBox1 + NounBox2;//名词合并
NounBox2 = "";//合并后,置空
if (NounBox3 != "")
{
NounBox2 = NounBox3;//填补置空的值,否则NounBox1有值,NounBox2为空,NounBox3又有值,就间隔了
NounBox3 = "";//合并后,置空
if (NounBox4 != "")
{
NounBox3 = NounBox4;
NounBox4 = "";//合并后,置空
}
}
}
}
/*
//判断NounBox2和NounBox3的名词是否需要合并
if (NounBox2 != "" && NounBox3 != "")
{
res = "";
//判断NounBox2和NounBox3之间是否有内容,如果没内容(res为空),就说明NounBox2和NounBox3是连续的名词,需要合并
res = dan.Substring(dan.IndexOf(NounBox2) + NounBox2.Length, dan.IndexOf(NounBox3) - (dan.IndexOf(NounBox2) + NounBox2.Length));
if (res == "")
{
NounBox2 = NounBox2 + NounBox3;//名词合并
NounBox3 = "";//合并后,置空
if (NounBox4 != "")
{
NounBox3 = NounBox4;//填补置空的值
NounBox4 = "";//合并后,置空
}
}
}
//判断NounBox3和NounBox4的名词是否需要合并
if (NounBox3 != "" && NounBox4 != "")
{
res = "";
//判断NounBox3和NounBox4之间是否有内容,如果没内容(res为空),就说明NounBox3和NounBox4是连续的名词,需要合并
res = dan.Substring(dan.IndexOf(NounBox3) + NounBox3.Length, dan.IndexOf(NounBox4) - (dan.IndexOf(NounBox3) + NounBox3.Length));
if (res == "")
{
NounBox3 = NounBox3 + NounBox4;//名词合并
NounBox4 = "";//合并后,置空
}
}
*/
}
//动词排序
void VerbOrder()
{
/*
如果不排序会怎样?句子中找到的第一个动词,可能不是谓语动词,而是宾语补足语动词,以宾语补足语动词分割句子,就错了。
谓语动词和宾语补足语动词,先找到哪个,取决于这两个词,谁在动词表前面排序,而动词的排序是不可知的,或许按笔划排序,或者按首字母排序
*/
string temp = "";//临时变量
if (VerbBox1 != "" && VerbBox2 != "")//招到了个动词,放在VerbBox1和VerbBox2
{
if (dan.IndexOf(VerbBox1) > dan.IndexOf(VerbBox2))//如果VerbBox1的动词在句子中的位置大于VerbBox2的动词在句子中的位置
{
//交换位置,在句子中位置小动词的放前面,从而确保VerbBox1放的是谓语动词,而宾语补足语动词放到VerbBox2
temp = VerbBox1;
VerbBox1 = VerbBox2;
VerbBox2 = temp;
}
}
if (VerbBox3 != "")
{
if (dan.IndexOf(VerbBox1) > dan.IndexOf(VerbBox3))
{
temp = VerbBox1;
VerbBox1 = VerbBox3;
VerbBox3 = temp;
}
if (dan.IndexOf(VerbBox2) > dan.IndexOf(VerbBox3))
{
temp = VerbBox2;
VerbBox2 = VerbBox3;
VerbBox3 = temp;
}
}
FindVerb = VerbBox1;
}
//动词结合成动词词组
void VerbJoin()
{
//动词合并:例如“应该爱”是两个动词:情态动词“应该”和普通动词“爱”,应该合并成一个动词
string res;
//判断VerbBox1和VerbBox2的动词是否需要合并
if (VerbBox1 != "" && VerbBox2 != "")
{
res = "";
//判断VerbBox1和VerbBox2之间是否有内容,如果没内容(res为空),就说明VerbBox1和VerbBox2是连续的动词(中间没有字符间隔),需要合并
res = dan.Substring(dan.IndexOf(VerbBox1) + VerbBox1.Length, dan.IndexOf(VerbBox2) - (dan.IndexOf(VerbBox1) + VerbBox1.Length));
if (res == "")
{
VerbBox1 = VerbBox1 + VerbBox2;//名词合并
FindVerb = VerbBox1;
VerbBox2 = "";//合并后,置空
if (VerbBox3 != "")
{
VerbBox2 = VerbBox3;//填补置空的值,否则VerbBox1有值,VerbBox2为空,VerbBox3又有值,就间隔了
VerbBox3 = "";//合并后,置空
if (VerbBox4 != "")
{
VerbBox3 = VerbBox4;
VerbBox4 = "";//合并后,置空
}
}
}
}
}
//谓语动词的发生概率
void VerbRateJudge()
{
/*
动词前面是否有否定词,也很重要。
例如“他爱猫”和“他不爱猫”,虽然谓语动词都是“爱”字,但前面加个“不”字,意义就相反了。所以看谓语动词前面是否有否定词,是很重要的事。
谓语动词前面的否定词,一般有不、不要、不可以、不应该、不能、别。
还有不确定肯定还是否定动词,例如“他不一定去”,“去”字是动词,但是动词前的“不一定”,并不像是“不”字那样对动词进行否定,而是对动词既不像是肯定,也不像是否定,而是不确定。
因此对每句话的谓语动词,都要加一个性质:肯定、否定、不确定。
但不确定,有时候偏向于肯定,例如“他可能去”。有时候不确定偏向于否定,例如“他不太可能去”以及“他或许不去”。
那么动词发生概率分为五种:肯定、偏向肯定、不确定、偏向否定、否定。
这其实就是在分析事情(谓语动词)发生的概率,这在概率分析上有用。
指定词语左边1个字符:str.Substring(str.IndexOf(word) - 1, 1);
指定词语左边1个字符:str.Substring(str.IndexOf(word) - 2, 1);
*/
VerbRate = "肯定";//默认值:肯定
string temp = "";//临时变量
//先判断谓语动词左边的1个字符,是否是否定词
temp = dan.Substring(dan.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不"))
{
VerbRate = "否定";
}
else if(temp.Contains("别"))
{
VerbRate = "否定";
}
//判断谓语动词左边的2个字符,是否是否定词
temp = dan.Substring(dan.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不要"))
{
VerbRate = "否定";
}
else if (temp.Contains("不能"))
{
VerbRate = "否定";
}
else if (temp.Contains("可能"))
{
VerbRate = "不确定";
}
else if (temp.Contains("或许"))
{
VerbRate = "不确定";
}
//判断谓语动词左边的3个字符,是否是否定词
temp = dan.Substring(dan.IndexOf(FindVerb) - 1, 1);
if (temp.Contains("不可以"))
{
VerbRate = "否定";
}
else if (temp.Contains("不应该"))
{
VerbRate = "否定";
}
}
//找形容词
string SearchAdj(string str)
{
string jieguo = "不包含";//默认值是不包含
int m = adj.Length;//形容词数组的长度,也就是有多少个形容词
string temp = "";
for (int n = 0; n < m; n++)
{
/*Contains函数用于判断包含关系,例如句子和形容词的包含关系
就是用句子和形容词数组的形容词,一一比对,来判断是否包含形容词
n的值从0逐渐增长到形容词数组的形容词数量值,这样数组也就经历了所有形容词
*/
if (str.Contains(adj[n]))//包含
{
jieguo = "包含";
temp = adj[n];
}
}
if (jieguo == "包含")//找到了形容词
{
return temp;
}
else
{
return "";
}
}
//找数词
void SearchNum(string str)
{
//先确定数词单位
int StrLength = str.Length;//全句长度
string temp = "";
string NumDanwei_type = "";//数字单位类型
string[] shuzu_danwei_mignci = new string[] { "个", "名", "位", "只", "头", "匹", "条", "棵", "朵", "片", "根", "座", "栋", "台", "部", "本", "块", "件", "盏", "把", "所", "辆", "艘", "架", "扇", "间", "包", "盒", "袋", "箱", "桶", "双" };
string[] shuzu_danwei_jiliang = new string[] { "米", "厘米", "毫米", "分米", "公里", "里", "微米", "纳米", "克", "斤", "公斤", "吨", "毫克", "升" };
//字符串从右向左,每次读取一个字符进行处理
for (int n = StrLength; n > 0; n--)
{
temp = str.Substring(n - 1, 1);//每次截取的一个字符,例如“年”字
if (NumDanwei_type == "")
{
//名词单位数组
foreach (string m in shuzu_danwei_mignci)//判断这个截取的字符是否在名词数组中
{
if (temp == m)//截取的字符属于名词数组(shuzu_danwei_mignci)中的字符,例如“个”字属于名词数组
{
NumDanwei = m;
NumDanwei_type = "名词单位";
SearchNum2(str, NumDanwei, NumDanwei_type);
if (num_type == "汉字型数字")
{
FindNum = SearchNum3(FindNum);
}
break;
}
}
}
if (NumDanwei_type == "")
{
//计量数组
foreach (string m in shuzu_danwei_jiliang)//判断这个截取的字符是否在计量数组中
{
if (temp == m)//截取的字符属于计量数组(shuzu_danwei_jiliang)中的字符,例如“米”字属于计量数组
{
NumDanwei = m;
if (str.Contains("厘"))
{
NumDanwei = "厘" + NumDanwei;
}
else if (str.Contains("毫"))
{
NumDanwei = "毫" + NumDanwei;
}
else if (str.Contains("公"))
{
NumDanwei = "公" + NumDanwei;
}
NumDanwei_type = "计量单位";
SearchNum2(str, NumDanwei, NumDanwei_type);
if (num_type == "汉字型数字")
{
FindNum = SearchNum3(FindNum);
}
break;
}
}
}
}
/*
找数字的其它方法:正则表达式。
需要using System.Text.RegularExpressions;//正则表达式找出数字所需
replace函数把不是数字的部分变为空无,这样就只剩下数字部分。
string res = "";
res = Regex.Replace(str, @"[^0-9]+", "");
return res;
*/
}
void SearchNum2(string str, string temp, string NumDanwei_type)
{
//找数字
string[] shuzu_num = new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" };
string[] shuzu_num_cn = new string[] { "一", "二", "两", "三", "四", "五", "六", "七", "八", "九", "零", "十", "百", "千", "万" };
//数量单位字符左边的字符串
string WordLeft = str.Substring(0, str.IndexOf(temp));//例如“有6米”的“有6”
//找阿拉伯数字,例如1、2、3这类数字
//逐一处理该字符左边的每个字符
int WordleftLength = WordLeft.Length;//例如“有6”这个字符串的长度
string temp2 = "";
//从右向左,逐字截取
for (int j = WordleftLength; j > 0; j--)
{
temp2 = WordLeft.Substring(j - 1, 1);//每次截取的一个字符
//从右到左,遇到不是数字的时候,就退出循环
if (temp2 != "1" && temp2 != "2" && temp2 != "3" && temp2 != "4" && temp2 != "5" && temp2 != "6" && temp2 != "7" && temp2 != "8" && temp2 != "9" && temp2 != "0")
{
break;
}
foreach (string m2 in shuzu_num)//判断这个截取的字符是否在数字数组中
{
if (temp2 == m2)//截取的字符属于数字数组(shuzu_num)中的字符,例如“1”字属于数字数组
{
if (NumDanwei_type == "名词单位" || NumDanwei_type == "计量单位")
{
//现在找出来的都是数字,但是都是倒序,需要拼接在一起
if (FindNum == "")
{
FindNum = temp2;
}
else
{
FindNum = temp2 + FindNum;
}
num_type = "阿拉伯数字";
}
}
}
}
if (NumDanwei_type == "名词单位" || NumDanwei_type == "计量单位")
{
if (FindNum == "")//没有找到阿拉伯数字
{
//找汉字型数字,例如一、二、三
WordleftLength = WordLeft.Length;//例如“有6”这个字符串的长度
temp2 = "";
//从右向左,逐字截取
for (int j = WordleftLength; j > 0; j--)
{
temp2 = WordLeft.Substring(j - 1, 1);//每次截取的一个字符
foreach (string m2 in shuzu_num_cn)//判断这个截取的字符是否在数字数组中
{
if (temp2 == m2)//截取的字符属于数字数组(shuzu_num)中的字符,例如“1”字属于数字数组
{
//现在找出来的都是数字,但是都是倒序,需要拼接在一起
if (FindNum == "")
{
FindNum = temp2;
}
else
{
FindNum = temp2 + FindNum;
}
num_type = "汉字型数字";
}
}
}
}
}
}
string SearchNum3(string find_num)
{
//汉字型数字转化为阿拉伯数字,例如“二十”转化为“20”
//这个转化有时候不准确
int old = 1;
int result = 0;
string temp = "";
int temp_num = 0;
//old(上一位数字)需要初始化为1,不能初始化为0,也不能不赋值
//因为如果数字开始(从左到右)第一个字符就是翻倍数(例如十),那么翻倍的上一位数(old)不能默认0或NULL
//如果翻倍数没有上一位数,拿默认1当上一位数(old初始化为1),翻倍数乘以1,就等于翻倍数翻倍自身,这样才正确
for (int n = 1; n <= find_num.Length; n++)
{
temp = find_num.Substring(n - 1, 1);//每次截取的一个字符
switch (temp)
{
case "一":
temp_num = 1;
break;
case "二":
temp_num = 2;
break;
case "两":
temp_num = 2;
break;
case "三":
temp_num = 3;
break;
case "四":
temp_num = 4;
break;
case "五":
temp_num = 5;
break;
case "六":
temp_num = 6;
break;
case "七":
temp_num = 7;
break;
case "八":
temp_num = 8;
break;
case "九":
temp_num = 9;
break;
case "零":
temp_num = 0;
break;
case "十":
temp_num = 10;
break;
case "百":
temp_num = 100;
break;
case "千":
temp_num = 1000;
break;
case "万":
temp_num = 10000;
break;
default:
break;
}
if (temp_num != 10 && temp_num != 100 && temp_num != 1000 && temp_num != 10000)//不是翻倍字符(十、百、千、万),而是0到9的数字
{
old = temp_num;//把数字存起来,下一次循环时,被下一位翻倍数所翻倍
if (n == find_num.Length)//当i的长度等于总数字的长度,也就是到了最后一位数(个位数),不用翻倍了
{
result = result + temp_num;//个位数不用翻倍,直接加
}
}
else//不是0到9的数字字符,而是翻倍字符,就要翻倍
{
//翻倍对象是上一位数字,就是old里存的数字。因为这次循环走else路线,所以temp_num没有赋值给old,因此old里还是上一位的数字
result = result + (old * temp_num);//此时的temp_num是翻倍单位(十、百、千、万),不是0到9的数字,翻倍上一位数字(old)
}
}
if (result != 0)
{
find_num = result.ToString();
return find_num;
}
else
{
return "";
}
}
//找时间(文字形式)
void SearchTime1(string str)
{
string[] shuzu_danwei_time1 = new string[] { "今天", "明天", "后天", "昨天", "前天", "这个月", "下个月", "上个月", "今年", "明年", "去年" };
string[] shuzu_danwei_time2 = new string[] { "早晨", "上午", "中午", "下午", "傍晚", "晚上", "傍晚", "夜晚", "半夜", "黎明", "黄昏", "清晨" };
string[] shuzu_danwei_time3 = new string[] { "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日", "礼拜一", "礼拜二", "礼拜三", "礼拜四", "礼拜五", "礼拜六", "礼拜天" };
string[] shuzu_danwei_time4 = new string[] { "春天", "夏天", "秋天", "冬天", "春季", "夏季", "秋季", "冬季" };
string[] shuzu_danwei_time5 = new string[] { "元旦", "大年三十", "除夕", "春节", "大年初一", "大年初二", "大年初三", "正月十五", "寒假", "清明节", "五一节", "劳动节", "儿童节", "暑假", "中秋节", "国庆节", "圣诞节", "假期", "休息日" };
foreach (string m in shuzu_danwei_time1)
{
if (str.Contains(m))
{
FindTime2 = m;
}
}
foreach (string m in shuzu_danwei_time2)
{
if (str.Contains(m))
{
FindTime2 = m;
}
}
foreach (string m in shuzu_danwei_time3)
{
if (str.Contains(m))
{
FindTime2 = m;
}
}
foreach (string m in shuzu_danwei_time4)
{
if (str.Contains(m))
{
FindTime2 = m;
}
}
foreach (string m in shuzu_danwei_time5)
{
if (str.Contains(m))
{
FindTime2 = m;
}
}
}
//找时间(年月日时分,布置框架)
void SearchTime2(string str)
{
//找年月日时分
string TimeDanwei = "";
if (str.Contains("年"))
{
TimeDanwei = "年";
FindTime_year = SearchTime3(str, TimeDanwei);
}
if (str.Contains("月"))
{
TimeDanwei = "月";
FindTime_month = SearchTime3(str, TimeDanwei);
if (num_type == "汉字型数字")
{
FindTime_month = SearchNum3(FindTime_month);
}
}
if (str.Contains("日"))
{
TimeDanwei = "日";
FindTime_day = SearchTime3(str, TimeDanwei);
}
if (str.Contains("点"))
{
TimeDanwei = "点";
FindTime_day = SearchTime3(str, TimeDanwei);
}
if (str.Contains("分"))
{
TimeDanwei = "分";
FindTime_day = SearchTime3(str, TimeDanwei);
}
}
//找时间(年月日时分,具体找)
string SearchTime3(string str, string TimeDanwei)
{
//找数字
string num = "";
string[] shuzu_num = new string[] { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" };
string[] shuzu_num_cn = new string[] { "一", "二", "两", "三", "四", "五", "六", "七", "八", "九", "零", "十", "百", "千", "万" };
//数量单位字符左边的字符串
string WordLeft = str.Substring(0, str.IndexOf(TimeDanwei));
//找阿拉伯数字,例如1、2、3这类数字
//逐一处理该字符左边的每个字符
int WordleftLength = WordLeft.Length;//例如“有6”这个字符串的长度
string temp = "";
//从右向左,逐字截取
for (int j = WordleftLength; j > 0; j--)
{
temp = WordLeft.Substring(j - 1, 1);//每次截取的一个字符
//从右到左,遇到不是数字的时候,就退出循环
if (temp != "1" && temp != "2" && temp != "3" && temp != "4" && temp != "5" && temp != "6" && temp != "7" && temp != "8" && temp != "9" && temp != "0")
{
break;
}
foreach (string m in shuzu_num)//判断这个截取的字符是否在数字数组中
{
if (temp == m)//截取的字符属于数字数组(shuzu_num)中的字符,例如“1”字属于数字数组
{
//现在找出来的都是数字,但是都是倒序,需要拼接在一起
if (num == "")
{
num = temp;
}
else
{
num = temp + num;
}
num_type = "阿拉伯数字";
}
}
}
if (num == "")//没有找到阿拉伯数字
{
//找汉字型数字,例如一、二、三
WordleftLength = WordLeft.Length;//例如“有6”这个字符串的长度
temp = "";
//从右向左,逐字截取
for (int j = WordleftLength; j > 0; j--)
{
temp = WordLeft.Substring(j - 1, 1);//每次截取的一个字符
foreach (string m2 in shuzu_num_cn)//判断这个截取的字符是否在数字数组中
{
if (temp == m2)//截取的字符属于数字数组(shuzu_num)中的字符,例如“1”字属于数字数组
{
//现在找出来的都是数字,但是都是倒序,需要拼接在一起
if (num == "")
{
num = temp;
}
else
{
num = temp + num;
}
num_type = "汉字型数字";
}
}
}
}
if (num != "")
{
return num;
}
else
{
return "";
}
}
//地点
bool difang(string str, string word)
{
if (str.IndexOf(word) > 0)
{
string temp = str.Substring(str.IndexOf(word) - 1, 1);
if (temp == "在" || temp == "到" || temp == "去" || temp == "来")
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
//显示最终输出结果
void ShowResult()
{
UnityEngine.Debug.Log("第" + dan_num + "句:" + danju[dan_num-1]);
UnityEngine.Debug.Log("句型:" + SentenceType);
if (SentenceType == "主谓宾")//主谓宾句型
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("宾语:" + FindObject);
UnityEngine.Debug.Log("语态:" + yutai);
}
else if (SentenceType == "双宾语")
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("间接宾语:" + FindJianObject);
UnityEngine.Debug.Log("直接宾语:" + FindZhiObject);
}
else if (SentenceType == "宾语补足语")
{
UnityEngine.Debug.Log("主语:" + FindSubject);
UnityEngine.Debug.Log("谓语:" + FindVerb);
UnityEngine.Debug.Log("宾语:" + FindObject);
UnityEngine.Debug.Log("宾语补足语动词:" + FindBuVerb);
UnityEngine.Debug.Log("宾语补足语名词:" + FindBuNoun);
}
else if (SentenceType == "只有性质状态")
{
UnityEngine.Debug.Log("只有性质状态:" + dan);
}
UnityEngine.Debug.Log("动词发生概率:" + VerbRate);
//显示名词所有格
if (SubjectSuoyouge != "")
{
UnityEngine.Debug.Log("主语的名词所有格:" + SubjectSuoyouge);
}
if (ObjectSuoyouge != "")
{
UnityEngine.Debug.Log("宾语的名词所有格:" + ObjectSuoyouge);
}
if (JianSuoyouge != "")
{
UnityEngine.Debug.Log("间接宾语的名词所有格:" + JianSuoyouge);
}
if (ZhiSuoyouge != "")
{
UnityEngine.Debug.Log("直接宾语的名词所有格:" + ZhiSuoyouge);
}
if (BuSuoyouge != "")
{
UnityEngine.Debug.Log("宾语补足语的名词所有格:" + BuSuoyouge);
}
//显示形容词
if (SubjectAdj != "")
{
UnityEngine.Debug.Log("主语的形容词:" + SubjectAdj);
}
if (ObjectAdj != "")
{
UnityEngine.Debug.Log("宾语的形容词:" + ObjectAdj);
}
if (JianAdj != "")
{
UnityEngine.Debug.Log("间接宾语的形容词:" + JianAdj);
}
if (ZhiAdj != "")
{
UnityEngine.Debug.Log("直接宾语的形容词:" + ZhiAdj);
}
if (BuAdj != "")
{
UnityEngine.Debug.Log("宾语补足语的形容词:" + BuAdj);
}
//显示数词
if (SubjectNum != "")
{
UnityEngine.Debug.Log("主语的数词:" + SubjectNum);
}
if (ObjectNum != "")
{
UnityEngine.Debug.Log("宾语的数词:" + ObjectNum);
}
if (JianNum != "")
{
UnityEngine.Debug.Log("间接宾语的数词:" + JianNum);
}
if (ZhiNum != "")
{
UnityEngine.Debug.Log("直接宾语的数词:" + ZhiNum);
}
if (BuNum != "")
{
UnityEngine.Debug.Log("宾语补足语的数词:" + BuNum);
}
//显示时间
if (FindTime_year != "")
{
UnityEngine.Debug.Log("年:" + FindTime_year);
}
if (FindTime_month != "")
{
UnityEngine.Debug.Log("月:" + FindTime_month);
}
if (FindTime_day != "")
{
UnityEngine.Debug.Log("日:" + FindTime_day);
}
if (FindTime_hour != "")
{
UnityEngine.Debug.Log("时(几点):" + FindTime_hour);
}
if (FindTime_minute != "")
{
UnityEngine.Debug.Log("分(几分):" + FindTime_minute);
}
if (FindTime2 != "")
{
UnityEngine.Debug.Log("时间:" + FindTime2);
}
//显示地点
if (didian != "")
{
UnityEngine.Debug.Log("地点:" + didian);
}
GuessWord();//猜测词语
//tmpText.text = mes;
//清空变量
FindSubject = "";
FindVerb = "";
FindObject = "";
FindBuVerb = "";
FindBuNoun = "";
FindJianObject = "";
FindZhiObject = "";
yutai = "";
SubjectSuoyouge = "";
ObjectSuoyouge = "";
JianSuoyouge = "";
ZhiSuoyouge = "";
BuSuoyouge = "";
SubjectAdj = "";
ObjectAdj = "";
JianAdj = "";
ZhiAdj = "";
BuAdj = "";
SubjectNum = "";
ObjectNum = "";
JianNum = "";
ZhiNum = "";
BuNum = "";
}
//猜测词语
void GuessWord()
{
/*
不建议用猜测词语,因为如果一个词语,词库里没有,要靠程序猜测,那么游戏剧情肯定对这个词语没做任何准备,就算猜测出这个词,也没用。
例如张三爱雅娜,名词词库肯定没有“雅娜”这个词,但是谓语动词“爱”字右边的句子的两个字,显然是宾语名词,所以猜测词语是很容易猜测的。
就算猜测出宾语是雅娜,又怎样了呢,对雅娜的信息和属性,什么都没有设置,程序没法分析。甚至连雅娜到底是一个人还是一块石头,都没法分析。
那么张三带着雅娜去海边,到底是张三带着女人雅娜去海边,还是张三带着石头雅娜去海边,准备扔石头玩水漂。计算机分析程序一头雾水,所以猜测词语会降低计算机的分析能力。
还是勤快点吧,把词语录入词库,并给词语设置信息和属性。什么时候用猜测词语呢?词库词汇量还不够多的时候,只能靠猜词来补偿,但这不是长远的办法。
这就好比编程强调“对变量,要先定义,后使用”,猜测词语就好比不定义就直接使用。
猜测词语的原理:抽取掉已知的词语(词库里有的词语),剩下的未知的词语(词库里没有的词语),就是要猜测的词。
例如“张三喜欢美丽的雅娜”,谓语动词右边句是“美丽的雅娜”,词库已有的形容词是“美丽的”,抽取掉形容词“美丽的”,剩下的词语“雅娜”就是要猜测的宾语。
*/
string GuessObject = "";//猜测宾语
string GuessBuNoun = "";//猜测宾语补足语的名词
string GuessJian = "";//猜测间接宾语
string GuessZhi = "";//猜测直接宾语
string temp = "";//临时变量
//猜测主谓宾句型的宾语
if (SentenceType == "主谓宾")
{
if (FindObject == "")
{
temp = RightPart;//谓语动词右边句
if (ObjectSuoyouge != "")
{
temp = RightPart.Replace("ObjectSuoyouge", "");//把名词所有格变为空无,就是抽取掉
}
if (ObjectAdj != "")
{
temp = RightPart.Replace("ObjectAdj", "");//把形容词变为空无,就是抽取掉
}
if (ObjectNum != "")
{
temp = RightPart.Replace("ObjectNum", "");//把数词变为空无,就是抽取掉
}
if (temp != "")
{
GuessObject = temp;
}
}
}
//宾语补足语句型,猜测名词
//谓语动词和宾语补足语名词之间的字符串,就是要猜测的宾语名词
if (SentenceType == "宾语补足语")
{
if (FindObject == "")
{
temp = dan;
temp = dan.Substring(dan.IndexOf(FindVerb) + FindVerb.Length, dan.IndexOf(FindVerb) - (dan.IndexOf(FindVerb) + FindVerb.Length));
GuessObject = temp;
}
//宾语补足语句型,猜测宾语补足语名词
if (FindBuNoun == "")
{
temp = "";
temp = dan.Substring(dan.IndexOf(FindBuVerb) + FindBuVerb.Length, dan.Length - (dan.IndexOf(FindBuVerb) + FindBuVerb.Length));
if (temp != "")
{
GuessBuNoun = temp;
}
}
}
/*
猜测双宾语句型的直接宾语。
例如“张三给李四一个雅娜”,李四是间接宾语,也是词库已有的名词,雅娜是直接宾语,词库没有这个名词,只能靠猜测词语。
间接宾语和直接宾语之间,有一个定语(数词:一个),这个定语右边的词语,就是直接宾语,左边的名词就是间接宾语。
前面的程序里,如果双宾语句型,只找到一个宾语名词(直接宾语或间接宾语),那就转化为主谓宾句型了,因为主谓宾句型只有一个宾语。但实际上可能是双宾语句型中,有个宾语不属于词库,所以没找到。
如果谓语动词是给、给予,这是双宾语句型的标志动词,确实很可能是双宾语句型,那么就当双宾语句型去猜词吧。
*/
//猜测主谓宾句型的宾语
if (SentenceType == "主谓宾")//假如之前把双宾语句型误当主谓宾句型
{
if (FindVerb == "给" || FindVerb == "给予" || FindVerb == "送给" || FindVerb == "教")//双宾语句的标志动词
{
if (ObjectAdj != "")
{
//谓语动词右边句里,宾语形容词(ObjectAdj)的左边句
string temp_left = RightPart.Substring(0, RightPart.IndexOf(ObjectAdj));
//谓语动词右边句里,宾语形容词(ObjectAdj)的右边句
string temp_right = RightPart.Substring(RightPart.IndexOf(ObjectAdj) + ObjectAdj.Length, RightPart.Length - (RightPart.IndexOf(ObjectAdj) + ObjectAdj.Length));
if (temp_left != "")
{
GuessJian = temp_left;
}
if (temp_right != "")
{
GuessZhi = temp_right;
}
}
if (ObjectNum != "")
{
//谓语动词右边句里,宾语数词(ObjectNum)的左边句
string temp_left = RightPart.Substring(0, RightPart.IndexOf(ObjectNum));
//谓语动词右边句里,宾语数词(ObjectNum)的右边句
string temp_right = RightPart.Substring(RightPart.IndexOf(ObjectNum) + ObjectNum.Length, RightPart.Length - (RightPart.IndexOf(ObjectNum) + ObjectNum.Length));
if (temp_left != "")
{
GuessJian = temp_left;
}
if (temp_right != "")
{
GuessZhi = temp_right;
}
}
if (ObjectSuoyouge != "")
{
//谓语动词右边句里,宾语的名词所有格(ObjectSuoyouge)的左边句
string temp_left = RightPart.Substring(0, RightPart.IndexOf(ObjectSuoyouge));
//谓语动词右边句里,宾语的名词所有格(ObjectSuoyouge)的右边句
string temp_right = RightPart.Substring(RightPart.IndexOf(ObjectSuoyouge) + ObjectSuoyouge.Length, RightPart.Length - (RightPart.IndexOf(ObjectSuoyouge) + ObjectSuoyouge.Length));
if (temp_left != "")
{
GuessJian = temp_left;
}
if (temp_right != "")
{
GuessZhi = temp_right;
}
}
}
}
//显示结果
if (GuessObject != "")
{
UnityEngine.Debug.Log("猜测宾语:" + GuessObject);
}
if (GuessBuNoun != "")
{
UnityEngine.Debug.Log("猜测宾语补足语的名词:" + GuessBuNoun);
}
if (GuessJian != "")
{
UnityEngine.Debug.Log("猜测间接宾语:" + GuessJian);
}
if (GuessZhi != "")
{
UnityEngine.Debug.Log("猜测直接宾语:" + GuessZhi);
}
//清空变量
GuessObject = "";
GuessBuNoun = "";
GuessJian = "";
GuessZhi = "";
}
}
热门相关:黄金万两粤语 妻子的绝地反攻 让姐姐迈出一步的妻子