2024年8月19日更新:修正女主角有時候走路會抖動的問題,切換場景時,天色同步。
我不想和任何人說話,大家不要打擾我。
此頁面程式自動排版有問題,一些程式被移到程式框外面了。
下面一些內容會白屏幾秒鐘,可能因為程式框內容量太大,從載入第一個程式框那,就開始白屏了,圖片也要等一會才顯示。
這篇文章的主題:unity遊戲原始碼和教程:智慧分析話語的三維唯美世界。
遊戲開發語言:C#,資料庫:單機資料庫sqlite。
這個遊戲的原始碼(含教程文件)我放到了夸克網盤(連結於2024年8月19日更新):
https://pan.quark.cn/s/df8edccd4e7a
遊戲介面:
小區:
小區傍晚的雪:
小區的晚上:
家裡:
市中心:
市街道:
郊區:
2024年8月18日增加的場景:
學校:
走廊:
教室:
圖書館:
體育館:
食堂:
天色同步:從一個傳送點到下一個場景,天色保持不變。例如是晚上過去的,到下一個場景,還是晚上。
(一)宣告
小區場景的三維模型來自於UnityStore的unity包:Low Poly Japanese Housing Complex。很多人在用,所以我的遊戲和其他人的遊戲出現這個相同場景,不是抄襲。而且那只是個三維模型,程式要自己寫,每個人寫的程式是不同的。
市中心、市街道、郊區場景,來自UnityStore的unity包:258316_Anime_Tokyo_(Japanese_City),也有很多遊戲開發者在用這個場景三維模型。
人物三維模型來自於網路上大家常見、常用的三維人物模型,我做了骨骼繫結、蒙皮、走路動畫。
雪景程式來自於unity包:Global Snow,天空盒來自於unity包:AllSky。
學校場景,來自unity包:Japanese_School_Buildings_Kit。
學校樓道場景,來自unity包:Japanese School Corridor 2.0。
教室場景,來自unity包:Japanese Classroom Set。
圖書館場景,來自unity包:Japanese School Library Set。
食堂場景,來自unity包:Japanese School Cafeteria。
體育館場景,來自unity包:Japanese School Gym。
游泳池場景,來自unity包:Japanese School Pool Clean Dirty Set。
醫務室場景,來自unity包:Japanese School Infirmary Set。
(二)基本操作
W鍵(長按):向前走。
S鍵(長按):向後走。
A鍵(長按):向左轉。
D鍵(長按):向右轉。
滑鼠左右上下移動來控制攝像機視角(螢幕視角),人物前進方向自動朝向攝像機視角。
鍵盤右邊的方向鍵:上:抬高攝像機視角,下:降低攝像機視角,左:拉近攝像機視角,右:拉遠攝像機視角。
F鍵(單擊):第三人稱視角和第一人稱視角的切換。第三人稱視角適合用在街上,第一人稱視角適合用在家裡。
樓梯上不動的時候,把螢幕視角向上仰,就可以上樓梯了。
室外場景時:空格鍵(單擊):顯示或關閉文字的輸入輸出框(預設不顯示,需要點選空格鍵才顯示)。輸入完文字後,按Enter鍵傳送。
J鍵(單擊):女主角一鍵換服裝。
M鍵(單擊):背景音樂,繼續按,是下一首好聽的背景音樂。
數字鍵1(單擊):小區場景(預設場景)。
數字鍵2(單擊):市中心場景。
數字鍵3(單擊):市街道場景。
數字鍵4(單擊):郊區場景。
數字鍵5(單擊):學校。
數字鍵6(單擊):學校走廊。
數字鍵7(單擊):教室。
數字鍵8(單擊):圖書館。
數字鍵9(單擊):食堂。
數字鍵0(單擊):體育館。
Esc鍵(單擊):退出遊戲。
小區場景中:
H鍵(單擊):一鍵回家。
小區場景、市街道場景、郊區場景中:
L鍵(單擊):正常景色和雪景的切換。
小區場景和學校樓外場景中:
G鍵(單擊):自動尋路。第一次按G鍵,男主角和女主角分開,女主角停留在原地。男主角走遠後,第二次按G鍵,女主角會自動尋路來找男主角,到男主角身邊。
小區場景和市街道場景中:
K鍵(單擊):每點選一次,就變換一次天色。小區場景:淺夜→夜晚→白天→傍晚→夜晚→清晨→白天→陰天。市街道場景:傍晚→晚上→白天。
(三)
即便沒有安裝unity編輯器的情況下,play資料夾裡DreamStart.exe可以直接執行此遊戲。
unity的一份原始碼,只能適配一個編輯器版本,這個原始碼適配的是2022.3.38,其它版本開啟此原始碼,會故障。
unity匯入此專案時,不是匯入哪個具體啟動檔案,而是用unity Hub(unity啟動器)直接開啟(匯入)DreamStart資料夾。
如果unity編輯器沒有顯示場景,就在編輯器裡手動開啟park資料夾裡的Scenes資料夾裡的park場景檔案即可。
在unity編輯器介面,不要把視窗最大化後再執行遊戲,那樣執行不了。但可以在遊戲後,再最大化視窗。
地上的藍色,是自動尋路烘培的地面,遊戲執行時不顯示那藍色。
(四)話語分析
話語分析是有用的,假如遊戲中,你是隊長,帶著NPC隊友張三和李四,路上遇到蛇,你可以說“張三打蛇,李四保護張三。”這就需要先分析出主語、謂語、賓語,程式才能處理。
輸入完成後,按Enter鍵傳送。
示例:
輸入:貓吃鼠
顯示:主語:貓,謂語動詞:吃,賓語:鼠
輸入:白色的貓吃黑色的鼠
顯示:主語:貓,謂語動詞:吃,賓語:鼠,主語的形容詞:白色的,賓語的形容詞:黑色的
輸入:兩隻貓吃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);//輸入完成後,對Enter鍵的響應
//連線資料庫
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);//輸入完成後,對Enter鍵的響應
//連線資料庫
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);//輸入完成後,對Enter鍵的響應
//連線資料庫
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);//輸入完成後,對Enter鍵的響應
//連線資料庫
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);//輸入完成後,對Enter鍵的響應
//連線資料庫
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);//輸入完成後,對Enter鍵的響應(按Enter鍵傳送)
}
// 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();//關閉資料庫連線
}
//輸入完成後,按Enter鍵傳送,便開始執行此函式
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);//輸入完成後,對Enter鍵的響應(按Enter鍵傳送)
}
// 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();//關閉資料庫連線
}
//輸入完成後,按Enter鍵傳送,便開始執行此函式
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);//輸入完成後,對Enter鍵的響應(按Enter鍵傳送)
}
// 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();//關閉資料庫連線
}
//輸入完成後,按Enter鍵傳送,便開始執行此函式
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 = "";
}
}