首先來看一個問題
國際標准圖書編號(I2017-07-05SBN)由被破折號分開的10個數字組成,如0-670-82162-4。一個ISBN分成四個部分:組代碼、出版社代碼、書籍代媽(在該出版社內惟一)、校驗碼 ,例如,ISBN 0-670-82162-4的含義是:組代碼是0,表明這本書來自說英語的國家;出版社代碼為670,標識這本書是由Viking Press發行的;82162是這本書在Viking Press的編號;校驗碼的計算方法如下所示:
按如下方法計算一個總和:ISBN中第一個數字加上第二個數字的兩倍加第三個數字的三倍…,一直加到第九個數字的九倍為止。
將上述總和除以11得到余數,如果余數為10,則最后一個特征值為X;如果不為10,則最后一個特征值就是這個余數。
要求:設計一個類,類中有書名,ISBN,等信息,其中定義了類成員函數,要求通過函數對象,並輸入書的一切信息,同時設計一個函數來檢查ISBN是否正確;
編寫代碼時遇到問題:如果ISBN校驗碼錯誤,如何修改字符串中的校驗碼?范圍再大一點,也就是說,如何修改字符串中指定位置的字符串?這是一個問題!
對於上述問題給出以下思路:截取不需要修改的字符串並保存,定義新字符串並替換原來需要修改的子串,將新的多個字符串寫入流中,然后從流中寫到最終的正確的字符串。
那么截取字符串,又該怎么做呢?網上搜尋字符串截取函數未果,便決定自己寫一個函數來實現。
注意到stringstream的方便特性,便有了思路。通過將字符逐個寫入流中再統一寫到新字符串中去便可以實現;
以下給出代碼:
1 /* 2 函數功能:字符串截取 3 參數:字符串 4 返回值:截取的字符串 5 */ 6 string cutStr(string str,int begin, int end){ 7 stringstream stream; 8 string newStr; 9 stream.clear(); 10 int i = 0; 11 for(i=begin; i<=end; i++){ 12 stream<<str[i]; 13 } 14 stream>>newStr; 15 return newStr; 16 }
這樣就實現了字符串截取函數。
最終問題得以解決:通過多次截取修改,便可以實現修改字符串指定位置上的字符
以下為初始問題代碼:
1 #include<iostream> 2 #include<string> 3 #include<sstream> 4 using namespace std; 5 6 class BOOK{ 7 protected: 8 string name; 9 string author; 10 string date; 11 string ISBN; 12 string price; 13 public: 14 //創建類對象 15 BOOK create(); 16 //檢查ISBN 17 void checkISBN(); 18 //打印 19 void print(); 20 }; 21 22 23 /* 24 函數功能:打印 25 參數:無 26 返回值:無 27 */ 28 void BOOK::print(){ 29 cout<<"信息如下:"<<endl; 30 cout<<"書名:"<<this->name<<endl; 31 cout<<"作者:"<<this->author<<endl; 32 cout<<"出版日期:"<<this->date<<endl; 33 cout<<"ISBN:"<<this->ISBN<<endl; 34 cout<<"價格:"<<this->price<<endl; 35 cout<<"---------------------------------------------------------------"<<endl; 36 } 37 38 /* 39 函數功能:字符串截取 40 參數:字符串 41 返回值:截取的字符串 42 */ 43 string cutStr(string str,int begin, int end){ 44 stringstream stream; 45 string newStr; 46 stream.clear(); 47 int i = 0; 48 for(i=begin; i<=end; i++){ 49 stream<<str[i]; 50 } 51 stream>>newStr; 52 return newStr; 53 } 54 55 /* 56 函數功能:檢查ISBN 57 參數:無 58 返回值:正確的ISBN 59 */ 60 void BOOK::checkISBN(){ 61 //寫一個字符串截取函數 62 string ISBN = cutStr(this->ISBN,0,11); 63 //0-670-82162-4 64 //0123456789012 65 stringstream stream; 66 //用循環來計算校驗碼 67 int i = 1; 68 int j = 0; 69 int sum = 0; 70 int num = 0; 71 while(i<=9 && j<=11){ 72 if(ISBN[j]=='-'){ 73 j++; 74 continue; 75 }else{ 76 stream<<ISBN[j]; 77 stream>>num; 78 num = i * num; 79 sum = sum + num; 80 i++; 81 j++; 82 stream.clear(); 83 } 84 } 85 86 87 sum = sum%11; 88 if(sum==10) sum=0; 89 stream<<(this->ISBN)[12]; 90 stream>>num; 91 stream.clear(); 92 //檢查並改正 93 if(num != sum){ 94 stream<<ISBN<<sum; 95 stream>>this->ISBN; 96 cout<<"ISBM有誤,已幫您修改!"<<endl; 97 } 98 99 } 100 101 /* 102 函數參數:創建類對象 103 參數:無 104 返回值:類對象 105 */ 106 BOOK BOOK::create(){ 107 BOOK book; 108 cout<<"書名:"; 109 cin>>book.name; 110 cout<<"作者:"; 111 cin>>book.author; 112 cout<<"出版日期:"; 113 cin>>book.date; 114 cout<<"ISBN:"; 115 cin>>book.ISBN; 116 cout<<"價格:"; 117 cin>>book.price; 118 //檢查ISBN,如果錯誤提示改正 119 //寫一個檢查ISBN的函數 120 book.checkISBN(); 121 cout<<"---------------------------------------------------------------"<<endl; 122 return book; 123 } 124 int main(){ 125 BOOK book=book.create(); 126 book.print(); 127 return 0; 128 }
編寫至此,產生一個新問題:這種方法繁瑣,需要頻繁寫入流中,如何更有效率的截取字符串?
另外,如何把一個字符串分為眾多的子串?在修改時便可不必反復截取,節省時間,節省精力!
筆者不精,偶有所得,文中若有不妥之處,歡迎前來指正!
若有此類想法或見解,亦歡迎前來交流!
