中文重復統計器
文字重復統計是一個使用文本處理工具, 輸入文本內容并指定最小詞長度后, 就能自動高亮顯示重復的詞。 本教程將會借助AI實現這個應用的開發
頁面腳本編寫
該工具的基礎流程較為清晰:用戶輸入一段文字后,調用提取算法處理重復詞匯,據此可提出以下問題
提問 (Round 1)
export default {name: 'HighlightText',state: {originalText: '', // 需要處理的文本textMinLenth: 2, // 最小詞長度duplicated: [], // 重復的單詞},actions: {extractText () { // 提取重復文本}}
}
上述腳本實現extractText方法 對state.originalText 提取出重復的文本,根據textMinLenth
最小詞長度(最小為2) 將結果寫入duplicated, 每項包含結果詞及高亮顏色(要求不同)。
同時統計文本換行、符號、和字符數也寫入state
返回
extractText() {// 重置狀態this.state.duplicated = [];// 統計換行符數量const lineCount = (this.state.originalText.match(/\n/g) || []).length;// 統計符號數量(非字母、數字、空格和換行符)const symbolCount = (this.state.originalText.match(/[^a-zA-Z0-9\s\n]/g) || []).length;// 統計字符總數(包括空格和換行符)const charCount = this.state.originalText.length;// 更新統計信息this.state.lineCount = lineCount;this.state.symbolCount = symbolCount;this.state.charCount = charCount;// 提取單詞并統計詞頻const words = this.state.originalText.toLowerCase().match(/[a-z0-9]+/g) || [];const wordCount = {};words.forEach(word => {if (word.length >= this.state.textMinLenth) {wordCount[word] = (wordCount[word] || 0) + 1;}});// 找出重復的單詞const duplicatedWords = Object.entries(wordCount).filter(([word, count]) => count > 1).map(([word, count]) => word);// 為每個重復的單詞分配不同的高亮顏色const colors = ['rgba(255, 99, 132, 0.5)', // 紅色'rgba(54, 162, 235, 0.5)', // 藍色'rgba(255, 206, 86, 0.5)', // 黃色'rgba(75, 192, 192, 0.5)', // 綠色'rgba(153, 102, 255, 0.5)', // 紫色'rgba(255, 159, 64, 0.5)', // 橙色'rgba(231, 233, 237, 0.5)' // 灰色];// 為每個重復的單詞創建對象,包含單詞和顏色this.state.duplicated = duplicatedWords.map((word, index) => ({word,color: colors[index % colors.length]}));
}
AI迅速理解了需求并在短時間內給出了算法結果。遺憾的是,該算法無法有效提取中文內容。
通過分析結果可以看出,該工具在處理重復內容時采用了與英文相同的邏輯,將空格或標點作為單詞分隔的依據。然而,這種處理方式并不適用于中文(事實上,使用國外的重復檢測工具也會得出相同結論)。
提問 (Round 2)
就這個問題再次提問后,AI回答
你指出的問題很關鍵,中文文本的分詞確實需要特殊處理。之前的實現依賴空格來分割單詞,這對中文無效。我將修改代碼,使用更適合中文的分詞方式。
同時它還說
這個實現應該能滿足中文文本的重復詞統計需求。如果你需要更復雜的中文分詞(例如按詞語而不是單字),可能需要集成專門的中文分詞庫,如 jieba 或 segmentit。
中文分詞確實是一個專門的領域。盡管如此,我還是嘗試用改進后的算法,但早已預料到效果可能不佳。果然,算法未能正確統計中文內容。通過觀察發現,AI在處理時出現了顧此失彼的問題:將每個中文字符都視為獨立單詞,再加上最小長度的限制條件,最終導致統計失敗。
提問 (Round 3)
我繼續提問:
上述算法,中文也是要求大于最小長度才納入統計的,不能把每個字作為一個詞
然后AI回答
你是對的,我之前的實現錯誤地將每個中文字符單獨作為一個詞統計了。現在我將修改代碼,讓中文和英文都遵循 textMinLenth 的限制,按連續字符作為詞進行統計。
返回的代碼仍存在準確性不足的問題。我發現它先進行了分詞操作再進行統計,而該算法在實際應用中難以奏效。至此,我確實感到有些失望,但仍需進一步給出提示。
提問 (Round 4)
提問:
我想要的是先統計重復,例如 你好會匹配所有你好。 而不是先分詞出你好
這一次終于有了轉機,因為他提到了一個我之前從未聽說的算法——滑動窗口。光是這個名字,就讓我覺得很有希望。于是我試著輸入了一段中文來測試效果。
觀察發現,統計結果并非完全準確。例如,4%的球員與4%與%的球員存在重復統計的情況。盡管如此,總體而言,該結果仍具有相當的準確度。
提問 (Round 5)
為了安慰它,這次我說
基本正確了。 但是還有2個問題: 1、中文的逗號、句號等符號不能作為重復統計。 2、還存在一個長字符串 會匹配到2個不同短的字符串的情況。 這看起來無法避免, 能否將算法調整為統計作為重復后, 內容就不參加其他的重復統計了
很幸運的是AI也完全理解了問題
我理解了你的需求,現在需要解決兩個關鍵問題:排除中文標點符號的干擾,以及避免重復統計重疊的文本片段。這需要更復雜的匹配策略和后處理邏輯。
雖然理解,但AI給出的算法仍然無法滿足要求。
提問 (Round 6)
還是計算不出結果。 還不如最早的幾個版本。 是否可以這樣, 首先將中文標點替換為空格,然后對中文字符使用滑動窗口算法, 并且空格就默認為分詞標志
這回終于, 它給出了一個還不錯的算法
extractText() {// 重置狀態this.state.duplicated = []// 統計換行符數量const lineCount = (this.state.originalText.match(/\n/g) || []).length// 統計符號數量(非字母、數字、中文、空格和換行符)const symbolCount = (this.state.originalText.match(/[^a-zA-Z0-9\u4e00-\u9fa5\s\n]/g) || []).length// 統計字符總數(包括空格和換行符)const charCount = this.state.originalText.length// 更新統計信息this.state.lineCount = lineCountthis.state.symbolCount = symbolCountthis.state.charCount = charCount// 預處理:將中文標點替換為空格const punctuationRegex = /[\u3000-\u303F\uFF00-\uFF60\uff0c\uff1a\uff1b\uff01\uff1f\uff0e]/gconst processedText = this.state.originalText.replace(punctuationRegex, ' ')// 提取所有可能的子串并統計頻率const substrCount = {}const minLength = Math.max(2, this.state.textMinLenth) // 確保最小長度至少為2// 按空格分割文本為單詞數組const words = processedText.split(/\s+/)// 對每個單詞使用滑動窗口提取所有可能的子串words.forEach(word => {if (!word) return // 跳過空單詞// 提取所有長度 >= minLength 的子串for (let i = 0; i < word.length; i++) {for (let j = i + minLength; j <= word.length; j++) {const substr = word.substring(i, j)substrCount[substr] = (substrCount[substr] || 0) + 1}}})// 找出重復的子串(出現次數 > 1),按長度降序排列const duplicatedSubstrs = Object.entries(substrCount).filter(([substr, count]) => count > 1).sort((a, b) => b[0].length - a[0].length)// 篩選最終結果,避免重疊const filteredSubstrs = []duplicatedSubstrs.forEach(([substr, count]) => {// 檢查是否已被更長的子串包含if (!filteredSubstrs.some(s => s.includes(substr) && s !== substr)) {filteredSubstrs.push(substr)}})// 為每個重復的子串分配不同的高亮顏色const colorVariations = ['#F53F3F', // semi-red-6'#EB2F96', // semi-pink-6'#722ED1', // semi-purple-6'#5B32C9', // semi-violet-6'#2F54EB', // semi-indigo-6'#1890FF', // semi-blue-6'#0FC6C2', // semi-light-blue-6'#00B42A', // semi-green-6'#7CB305', // semi-lime-6'#FACC14', // semi-yellow-6'#FF7D00' // semi-orange-6] // 為每個重復的子串創建對象,包含text和style屬性this.state.duplicated = filteredSubstrs.map((substr, index) => ({text: substr,style: {backgroundColor: colorVariations[index % colorVariations.length],color: '#fff',padding: 4}}))}
頁面制作
我將Bootstrap的多行輸入和高亮組件整合到頁面中,并設置按鈕點擊時觸發提取算法功能。 每次算法給出結果后,都可以快速驗證。
具體配置如下:
多行輸入:取值連接到”需要處理的文本“
高亮組件:內容連接到”需要處理的問題“, 高亮文本連接到”重復的單詞“
為了顯示哪些詞匯重復了,需要放入一個列表組件, 數據就連接到”重復的單詞“,在里面放入彈性容器/文本,
為頁面腳本庫增加計算2個字段如下,
...computed: {itemWordText: scope => scope.item.text, // 重復單項文本itemBackgroundColor: scope => scope.item.style.backgroundColor // 單項背景顏色}
...
}
將列表內的文本的內容和背景顏色分別連接到這2個字段 。這樣提取后右側會顯示重復詞列表
最后,增加一個watch字段,使得用戶修改文本時,直接進行統計無需再點擊按鈕。將之前按鈕刪除
watch: {originalText () {this.extractText()}},
最后,調整和美化整個頁面布局 這個工具就算制作好了
小結
- 相比之前的密碼生成器,這款統計重復算法的AI經過多次交互優化,最終呈現出令人滿意的效果。
- 從功能設計的角度來看,這個需求對人類程序員而言通常無需多次解釋。人類開發者完成編寫后,能夠自行驗證結果是否符合需求。但人工智能在這方面的能力明顯欠缺,需要反復澄清和細化具體要求。
- 當AI輸出結果不符合預期時,有些問題可以直接通過結果反饋發現,但有些需要深入代碼層面才能識別。這就要求使用者具備一定的代碼閱讀和理解能力,才能有效引導AI進行調整。從這個角度來看,AI更像是輔助工具而非開發的主導者。
- 保持耐心尤為關鍵
當算法多次輸出錯誤結果時,我的做法是明確指出初始版本更合適,并引導它僅針對特定方面進行調整。這很關鍵,因為雖然條條大路通羅馬,但人類通常更擅長找到更合理且復雜度更低的解決方案路徑。
最后的最后,從效率上來說,雖然多次提示并花時間去閱讀生成代碼給出解決建議,但AI整體輸出速度還是比我要快,并且更加省心。
大家可以通過這個地址訪問應用,
https://ridgeui.com/npm/ridge-duplicate/
或者通過設計器打開自己更改和驗證
https://ridgeui.com/npm/ridge-editor/?import=ridge-duplicate