NX二次開發-UFUN建立角度尺寸標註UF_DRF_create_angular_dim
此作業的要求參見:https://edu.cnblogs.com/campus/nenu/2020Fall/homework/11206
該作業採用的程式語言為Python,其程式碼的地址為:https://e.coding.net/xucancan1/count_words/count_words.git
我用的是git和tortoisgit將檔案傳入到coding.net上的
功能1小檔案輸入
功能2支援命令列輸入英文作品的檔名
功能3支援命令列輸入儲存有英文作品檔案的目錄名
功能4從控制檯讀入英文單篇作品
一. 功能1
重難點:
(1)對於第一個題,如何把檔名輸入到命令列引數上,讓命令列的引數來進行處理問題?注意這裡要與input()函式的輸入區分開來
如果我們使用input()函式獲得輸入資料而進行處理,這種在命令列上執行時,會要求敲兩次回車鍵才能執行,第一行輸入的資料都輸入到了sys.argv中,而第二行輸入的資料,才是被輸入到了input()了,然後通過input()來處理,雖然結果相同,但顯然不符合題意。
正確做法:引入sys包,通過sys,argv陣列來接收輸入的檔名以及其他引數 (ps:不是用input來接受檔名進行處理)
(2)如何通過命令列輸入的檔名來讀取對應的檔案?
通過使用sys.argv[0],sys.argv[1],sys.argv[2],來進行操作,一般sys.argv[0]指的是pthon檔名的路徑,sys.argv[1],sys.argv[2],才是接下來的要處理的引數
對於開啟檔案用open()函式:f=open("sys.argv[0]",''r",encoding="UTF-8"),這裡有一個很容易錯的問題,那就是這個需要加一個utf-8,當時在這個問題卡了很久,不明白問題所在,通過百度才明白。
由於.py檔案預設ASCII編碼,中文在顯示時會做一個ASCII到系統預設編碼的轉換,這時會報錯,所以在open()函式里加‘encoding='utf-8’,意為以位元組為單位對Unicode進行編碼儲存,這樣遇到中文也不會出錯。
(3)如何將檔案的內容分割成單詞,然後儲存到列表中?
我用的是split()函式按照一定的規則進行分割;首先將檔案統一轉換成小寫(大寫也行)進行預處理,避免重複計算,
(4)如何統計總單詞數和統計各個單詞出現的次數?
對於這個問題,我本來想著用一個for迴圈來遍歷列表。將每個單詞出現的個數用字典來統計的,但是後來想了一下這個有點浪費體力,然後剛好有一個collection包裡有一個counter()函式,直接統計列表中的單詞,返回的結果是一個元組的列表,剛好符合我要的功能。接著就是遍歷這個字典統計各個單詞的出現的個數以及進行列印。
(5)如何統計單詞數出現最多的前n個單詞的列表?
這裡其實可以使用sort函式對字典的鍵值進行排序,然後選擇只打印前10個單詞以及出現的個數,但是這樣多了一個for迴圈判斷,我果斷放棄了,又選擇一個一個內建函式most_common(10),這個函式好處作用是統計了前10的單詞,返回是一個字典,然後只需列印遍歷這個字典就行。
重要程式碼:
#功能1:小檔案輸入。 def count_words(filename): #print("c") s=".txt" if s in filename: path=filename else: path=filename+s try: with open(path,"r",encoding="UTF-8") as f_obj: content = f_obj.read().lower() except FileNotFoundError: msg = "sorry,the file " + filename + " does not exist." print(msg) else: #為避免重複計算大小寫單詞,所以將所有單詞全部轉換為小寫 lists= re.split(r'[",", ".", "!", "?", ";", ""","--","\n"]', content) #通過正則表示式和split()函式生成檔案內容的列表 lists= list(filter(None, lists)) #消除列表中的空格 words=Counter(lists) #遍歷字典,統計鍵值對數 num=0 for key,value in words.items(): num+=1 #功能1不輸出words,功能2輸出words if sys.argv[1]=="-s": print("total"+" "+str(num)) else: print("total"+" "+str(num)+" words") #most_common(n)返回統計單詞數出現最多的前n個單詞列表 maxwords=words.most_common(10) for i in maxwords: print("%-10s%5d"%(i[0],i[1]))
執行效果截圖:
二. 功能2
重難點:
(1)如何支援直接輸入檔名,而不需要加字尾名.txt和-s就可以統計檔案的各個單詞次數呢?
對於這個問題,要與第一題區分,第一題是加-s就執行執行這個檔案,我們只要判斷一下sys,argv[1]是否是-s,如果有,就執行第一個功能,如果沒有就執行第二個功能,接著然後在輸入的檔案後面新增一個.txt字尾。
(2)如何處理這個檔案的大小寫單詞和非字母對單詞詞統計的影響?
對於這兩個問題,當統計次數時,首先解決大小寫的影響,我用的是.lower()函式將全部單詞轉化為小寫,(這裡也可以用.upper()函式轉換成大寫),這樣做可以避免重複計算單詞。其次是解決非字母的字元,我使用的是findall(r"[a-z0-9^-]+",f.read().lower())函式來處理的,它的作用是通過正則表示式和findall()函式排除不符合的字元,從而生成檔案內容的列表,其實我後來想了一下,其實也可以用replace()函式把那些不符合單詞的字元替換掉。
(3)有關功能1和功能2的區別?
功能1和功能2除了上述的輸入有區別外,還有輸出的區別:功能2是要輸出“words”這個單詞的,功能1不輸出該單詞。
重要程式碼:
#功能2:支援命令列輸入英文作品的檔名 def count_words02(name): # 判斷傳入的命令列引數字尾部分是否含有.txt d=".txt" if d in name: path=name else: #若沒有,要加上,再作為開啟路徑 path=name+d f=open(path,"r",encoding="utf-8") lists=findall(r"[a-z0-9^-]+",f.read().lower())#通過正則表示式和findall()函式生成檔案內容的列表 words=Counter(lists) #遍歷字典,統計鍵值對數 num=0 for key,value in words.items(): num+=1 #功能1不輸出words,功能2輸出words if sys.argv[1]=="-s": print("total"+" "+str(num)) else: print("total"+" "+str(num)+" words") #most_common(n)返回計數值最大的n個元素的元素列表 maxwords=words.most_common(10) for i in maxwords: print("%-10s%5d"%(i[0],i[1]))
執行效果截圖:
三.功能3
重難點:
(1)如何判斷你輸入的引數是檔案還是資料夾?
對於這個問題,我百度了一下,首先需要os這個包,這個包裡面帶了一個os.path.isdir()函式,它的作用是用於判斷某一物件(需提供絕對路徑)是否為目錄,這個要與os.path.isfile()函式區分開來他的作用是判斷物件是否為一個檔案,具體用法區別詳見:https://blog.csdn.net/m0_37443131/article/details/81231763
(2)如何獲取當前.txt檔案的絕對路徑?
這個問題困擾了很久,我當時想取指定檔案或目錄的絕對路徑(完整路徑),想起OS模組不是有個取檔案絕對路徑的方法os.path.abspath(),結果出現了很大的問題。
例如:獲取檔案‘test.py’的完整路徑
test.py的完整路徑是:D:\python_t\IO目錄處理\test.py,而不是D:\python_t\test.py,看到這個結果我就淚奔了,不是取絕對路徑麼?怎麼不是真實的完整路徑?上級目錄不見了?很多疑惑?
其實通過這個例子,我們可以看出os.path.abspath()函式無法獲取指定檔案的絕對路徑,而是需要加檔案路徑os.path.abspath(path),所以我為了獲得絕對路徑,分為了兩個部分,第一部分是獲得該資料夾的上級目錄domain = os.path.abspath("."), domain獲取的是當前檔案的上一級目錄資料夾,然後加上當前資料夾;第二部分是獲得需要訪問的.txt檔案,兩個部分加起來,就是.txt檔案的絕對路徑。
詳細用法:https://blog.csdn.net/funnypython/article/details/78733115
(3)在獲得資料夾路徑時,需要把所有的\\更改為/
因為python返回路徑時目錄級別都是\\這個形態的,需要將他轉換成 / 這個形態,用了replace()函式替換
(4)如何統計資料夾下的.txt檔案的單詞出現次數?
由於獲得了該資料夾的絕對路徑,再加上需要訪問的.txt檔案,兩部分加起來就是該.txt檔案的絕對路徑,然後用open()函式,對這個檔案進行讀取,去除一些不符合單詞的字元,然後用counter()函式統計單詞出現的個數。
重要程式碼:
#功能3 elif os.path.isdir(sys.argv[1]): #print(sys.argv[1]) filecount(sys.argv[1])
#功能3:傳入資料夾,批量統計資料夾下各檔案的單詞的個數 def filecount(filename): files=os.listdir(filename)#將資料夾下的檔案列表化 # print(files) #輸出該檔案下所有的檔案 print("\n") domain = os.path.abspath(".") #獲取檔案的上一級目錄資料夾,輸出的是D:/homework01/ domain = domain.replace('\\', '/') + '/' + filename + '/' #將所有的\\變成“/”,且加上當前檔案,返回相當於D:/homework01/book/ for file in files: #遍歷檔案下的所有檔案 path=domain+file #這才是該檔案的真實路徑,path=D:/homework01/book/file.txt (filename1, extension) = os.path.splitext(file)#將檔名與字尾分開,將檔名單列出來 print(filename1) f=open(path,"r",encoding="utf-8") lists=findall(r"[a-z0-9^-]+",f.read().lower())#通過正則表示式和findall()函式生成檔案內容的列表 words=Counter(lists) #Counter函式是用來跟蹤值出現的次數,以字典的鍵值對形式儲存,其中元素為key,其計數為value #遍歷字典,統計鍵值對數 num=0 for key,value in words.items(): num+=1 print("total"+" "+str(num)+" words") #most_common(n)返回計數值最大的n個元素的元素列表 maxwords=words.most_common(10) for i in maxwords: print("%-10s%5d"%(i[0],i[1])) print('------------------')
執行效果截圖:
四.功能4
重點難點:
(1)如何對功能4的理解?
其實開始看這個功能4時,我還蒙,但是看了一下測試用例,我慢慢明白了,首先確定the_show_of_the_ring是一個檔案,其次哪個>wf -s < the_show_of_the_ring,這個<符號是一個重定向符,-s是新增的區別於其他功能的標誌,所以題意是統計重定向的檔案的單詞個數。
(2)如何在cmd命令臺接收一大段英文文章?
首先確定sys.argv陣列是不能接受這麼大段英文文章的,所以我引用了input()函式,sys.argv用來儲存這個.py檔案路徑,我先判斷一下輸入,sys.argv陣列的裡面內容的個數為1,就表明它接下來要輸入一段英文文章;接著我用input()函式來接收這段英文。然後通過input()函式接收的英文進行分割處理成單詞列表,接下來就是統計單詞個數了
重要程式碼:
#功能4:輸入一篇文章統計單詞字數 if(len(argv)==1): str = input() str = re.sub('[^a-zA-Z]',' ',str) #sub()函式將不為字母的替換空格 count_words03(str)
(3)如何統計重定向檔案的單詞,即< the_show_of_the_ring?
對於這個問題,我完全沒有頭緒,後來通過偉大的百度,查閱了一下windows下檔案重定向的相關問題,大概總算明白了是什麼回事。然後看到了一個sys.stdin.readline() 函式,這個函式功能是儲存重定向的檔名接著去讀這個檔案的內容,返回這個檔案的內容。剛好返回的內容是我們需要的,我們可以通過相關處理變成單詞列表,繼續統計該列表的單詞。
sys.stdin.readline()函式用法詳見:https://www.jb51.net/article/169914.htm
(4)如何判別wf.py -s是執行功能4的重定向呢?
這個功能區別於功能1,功能1中的sys.argv數組裡面的len(sys.argv)是3,而功能4中的len(sys.argv)數組裡面的是2,接下來用sys.stdin.readline() 函式接收重定向的檔案,並返回該檔案的內容。
重要程式碼:
#功能1和功能4 elif sys.argv[1]=='-s': if(len(argv) == 3): #執行功能1 #print(sys.argv[2]) count_words(sys.argv[2]) elif(len(argv)==2): #執行功能4:重新定向檔案 redirect_words = sys.stdin.readline() # 儲存重定向的檔名接著去讀這個檔案的內容,返回這個檔案
重要程式碼:
#功能4:重定向 def count_words03(string): print("\n") lists = string.replace('\n', ' ').lower().split() # 用空格去掉所有的\n,且轉換成小寫,進行分割單詞 words=Counter(lists) #Counter函式是用來跟蹤值出現的次數,以字典的鍵值對形式儲存,其中元素為key,其計數為value #遍歷字典,統計鍵值對數 num=0 for key,value in words.items(): num+=1 print("total"+" "+str(num)+" words") #most_common(n)返回計數值最大的n個元素的元素列表 maxwords=words.most_common(10) for i in maxwords: print("%-10s%5d"%(i[0],i[1])) #定義main函式 def main(argv): #功能4:輸入一篇文章統計單詞字數 if(len(argv)==1): str = input() str = re.sub('[^a-zA-Z]',' ',str) #sub()函式將不為字母的替換空格 count_words03(str) #功能1和功能4 elif sys.argv[1]=='-s': if(len(argv) == 3): #執行功能1 #print(sys.argv[2]) count_words(sys.argv[2]) elif(len(argv)==2): #執行功能4:重新定向檔案 redirect_words = sys.stdin.readline() # 儲存重定向的檔名接著去讀這個檔案的內容,返回這個檔案的內容 redirect_words= re.sub('[^a-zA-Z]',' ',redirect_words) count_words03(redirect_words)
執行效果圖:
五 功能5
在檔案中統計給定的單詞長度為m的次數前n個的單詞
重難點:
(1)如何解析題目的需求?
我為了把這個功能模組整合到原先設計好的程式框架中,特定對功能5做了標記,這是為了與其他功能的執行區分,用了-h這個標記來執行功能5,剩下的就是功能5的需求進行設計。
(2)如何將兩個變數引數輸入進去,並且讓它們執行相應的功能?
對於這個問題我是用input()函式來接收它們,由於input()函式返回的是字串型別,所以我用了int()函式將他們強制轉換成整形,然後把它們輸入到功能5模組中進行處理,接著就是讀取檔案,將檔案內容按照正則表示式分割成單詞列表。
#功能5: 在檔案中統計給定的單詞長度為m的次數前n個的單詞 if(sys.argv[1]=="-h"): str1=input() a=int((str1.strip())) str2=input() b=int((str2.strip()))) count_words04(sys.argv[2],a,b)
(3)注意input()函式,這個函式它也接收空格,回車換行等字元,在將它強制轉換時,需要用striip()將這些過濾掉,然後才能用int()函式轉成整數
(4)如何獲得檔案中單詞長度為m的單詞次數前n的單詞列表呢?
首先,解決這個問題分為兩步,第一步在檔案中獲取所有單詞長度為m的單詞;我先用counter()函式統計各個單詞的出現的次數,由於counter()函式返回的是單詞元組的列表,在這個問題,我開始以為counter()函式返回的是字典,後面造成了一定隱形錯誤,然後我遍歷這個列表,找出所有單詞長度為m的單詞,接著將它們逐個新增到一個空字典中;第二步在第一步的基礎上,統計單詞次數前n的單詞;由於獲得了所有單詞長度為m的單詞的字典,接著對這些字典的鍵值進行排序,我本來是想用一個氣泡排序進行排序的,後來想著這樣太麻煩了,所以直接用most_common()函式統計出前n的單詞 以及次數。
words=Counter(lists) #遍歷元組,統計鍵值對數 num=0 words_dic = {} for key,value in words.items(): d={} if(len(key)==lent): #統計長度為lent的單詞 d[key]=value words_dic.update(d) num+=1 print("\n") print("total"+" "+str(num)+" words") print("你選擇了長度為"+str(lent)+"的單詞") print("統計單詞數出現最多的前"+str(n)+"個單詞的列表") words_list=Counter(words_dic)
(5)關於most_common()函式的錯誤用法的血淚史。
錯誤1:呼叫most_common()函式有限制,我一直以為可以通過字典來呼叫它,然後我一直執行,不停的報錯,(ps:我英語差,當時看不懂錯誤提示)然後我將錯誤提示提交給百度,搜查相關的問題,然後知道了問題關鍵所在,原來是most_commom()函式的用法出現問題,接著我查了一下most_commom()函式的用法,字典不能呼叫它,列表可以呼叫它。然後我就再次使用counter()函式,將字典轉成帶有元組的列表,這樣就可以使用most_commom()函數了。
錯誤2:most_common()函式只返回前n個單詞,它不管第n+1個單詞是否與第n個單詞相等,這樣造成的後果會丟掉那些原本第n+1個單詞和第n個單詞相等的單詞。
錯誤執行結果截圖:
從上圖可以看出,長度為4的單詞排序,取單詞數出現前3的單詞,第4,第5,第6的單詞個數與第3的單詞個數相等,但是它們被捨棄了,沒有被顯示,這種返回結果非常不好。
針對上面的出現的問題,我重新定義了一個get_count(dct, n)函式來解決,當相等的情況下,相等的需要全部被顯示出來。
#返回統計單詞數出現最多的前n個單詞列表 def get_count(dct, n): data = dct.most_common() val = data[n-1][1] return list(takewhile(lambda x: x[1] >= val, data))
正確執行結果截圖:
重要程式碼:
def main(argv): #功能5: 在檔案中統計給定的單詞長度為m的次數前n個的單詞 if(sys.argv[1]=="-h"): str1=input() a=int((str1.strip())) str2=input() b=int((str2.strip())) count_words04(sys.argv[2],a,b)
#功能5:查詢特定長度單詞的個數 def count_words04(filename,lent,n): s=".txt" if s in filename: path=filename else: path=filename+s try: with open(path,"r",encoding="UTF-8") as f_obj: content = f_obj.read().lower() except FileNotFoundError: msg = "sorry,the file " + filename + " does not exist." print(msg) else: #為避免重複計算大小寫單詞,所以將所有單詞全部轉換為小寫 lists= re.split(r'[",", ".", "!", "?", ";", ""","--","\n"]', content) #通過正則表示式和split()函式生成檔案內容的列表 lists= list(filter(None, lists)) #消除列表中的空格 words=Counter(lists) #遍歷元組,統計鍵值對數 num=0 words_dic = {} for key,value in words.items(): d={} if(len(key)==lent): #統計長度為lent的單詞 d[key]=value words_dic.update(d) num+=1 print("total"+" "+str(num)+" words") print("你選擇了長度為"+str(lent)+"的單詞") print("統計單詞數出現最多的前"+str(n)+"個單詞的列表") print(words_dic) words_list=Counter(words_dic) # 本來想用most_common(n)返回統計單詞數出現最多的前n個單詞列表,後來當有多個單詞相等的時候,這個函式只取前n個,其實第n+1個也是跟第n值相等,但是這個函式不能實現 maxwords=get_count(words_list,n) #maxwords=words_list.most_common(n) print("\n") print("統計結果為:") for i in maxwords: print("%-10s%5d"%(i[0],i[1]))
執行結果截圖:
6.psp
功能 | 預計花費時間 | 實際花費時間 | 時間差 | 原因 |
功能1 | 80min | 123min | 43min | 對python命令臺輸入輸出不太熟悉 |
功能2 | 60min | 105min | 45min | 對引數輸入沒把握好,且處理字尾名花了一段時間 |
功能3 | 90min | 146min | 76min | 對於獲取絕對路徑不理解,花了很久解決這個問題 |
功能4 | 100min | 152min | 52min | 首先對題目的解析花了一段時間,且設計相關功能也花了很多時間 |
功能5 | 40min | 60min | 20min | 功能測試,以及功能設計需求超出了時間 |
測試 | 20min | 123min | 103min | 對於python檔案需要轉換成.exe檔案,安裝pyinstaller嚴重超出了時間 |
7.總結
完成這個部分作業,我大概分為了三個階段:
第一階段熟悉安裝使用git和totorisgit,熟練將檔案從coding.net或github中pull下來或者push到雲端。
第二階段1-5功能實現的程式碼設計
第三階段將.py檔案轉換成.exe檔案
對於第一階段,說句實話,花了很久時間才把totorisegit這個工具學會(當然也可以用git命令列),用它可以直接push&pull程式碼,而且可以將程式碼push到雲端儲存著,真的很方便,雖然在學習使用工具這個過程中摸索地很痛苦,但是學會了後,我感覺totorisgit工具和雲端倉庫真的太nice了!
對於第二個階段功能程式碼設計,python很多方法的實現完全可以呼叫相關函式來執行,我在這個問題上由於python知識儲備不是很足,所以花了很多時間研究其中的函式,最終才將相關的函式運用到實際操作中。個人建議:如若遇到不懂的盲點或者疑惑,可以自己先獨立去百度,知乎等搜尋,這樣可以全面徹底掌握自己的盲區和疑惑。
對於第三階段下載安裝pyinstaller,將.py檔案轉換成.exe檔案,真的我也摸索了很久。主要是在.exe檔案的查詢上,一開始不知道它轉化到哪裡了,後來查詢百度,發現它存到了dist檔案中
通過這次的程式設計實踐,讓我學習到了很多以前沒有學到的知識,同時也讓我知道了自己的不足,我還需要不停地努力!
關於totoisgit和git安裝是相關問題:
1.Git將原生代碼推到遠端倉庫的步驟:[https://blog.csdn.net/weixin_39910711/article/details/89955544]
2.利用totorisgit在github上下載程式碼:https://blog.csdn.net/zdp072/article/details/51966586
3.遠端倉庫連線錯誤時,如何清除連線[https://www.cnblogs.com/wollow/p/10840016.html]
4.認證失敗時,怎麼辦[https://www.jianshu.com/p/c095300d569e]
5.使用Git客戶端下載程式碼的流程[https://blog.csdn.net/wyqwilliam/article/details/82881609]
6.Git clone和Git pull的簡要區別[https://www.jianshu.com/p/c6a0397ec6f5]
7.如何將.py檔案轉化為可執行的.exe檔案:https://blog.csdn.net/qq_36604847/article/details/81509113