[分享] Split () 分割字串函數 |
尚未結案
|
l8939_c
一般會員 發表:9 回覆:15 積分:4 註冊:2005-03-07 發送簡訊給我 |
大家好, 小弟常在此地發問, 並且幾乎都能在短時間內獲得滿意的解答
雖然我對 C++ 還是個新手, 但最近模仿 VB 的 Split()函數寫了一個小程式
請大家參考看看, 並且提點改進的意見, 謝謝! 函數功能說明 : 輸入一個 String 字串,及分割字元, 傳回一個 String 陣列 String *Split(String s1,char k1) // 字串分割 使用範例 : String *aaa=Split(" 2 88 789 36 78",' ');
List1->Items->Add(aaa[2]);
====> 可得到 789 分割字元可以是逗號,分號,空白...... , 但不可以是 '~'
希望有人可以提供更好的方法, 避掉此一限制
另外,回傳的陣列不知有多大, 希望有人有辦法解決 以下是程式碼, 麻煩幫我試試是否有 bug, 或是是否能更簡潔
String *Split(String s1,char k1) // 字串分割 { if (k1==' ') { String s3;s3=s1.Trim(); for (int i=2;i
------
engineer |
kagaya
中階會員 發表:74 回覆:175 積分:59 註冊:2002-12-28 發送簡訊給我 |
這個函式我也常用.改成下面那樣就沒有~的問題了
用法
String s1="12,34,56,78";
String *s2=Split(s1,",");
t1->Text=s2[1];
至於陣列的長度.我也不知道該怎麼抓=.= String *Split(String str,String dot) //字串分割
{
int i=0,j=1,dot_len=dot.Length();
String str_temp=str;
while((i=str_temp.Pos(dot))>0){
j ;
str_temp=str_temp.SubString(i dot_len,str_temp.Length());
}
String *str_arr=new String[j];
if(j==1){
str_arr[0]=str;
}else{
j=0;
String str_temp=str;
while((i=str_temp.Pos(dot))>0){
str_arr[j]=str_temp.SubString(1,i-1);
j ;
str_temp=str_temp.SubString(i dot_len,str_temp.Length());
}
str_arr[j]=str_temp;
}
return str_arr;
}
------
KUSO 無處不在 |
l8939_c
一般會員 發表:9 回覆:15 積分:4 註冊:2005-03-07 發送簡訊給我 |
kagaya 你好 感謝你的建議,不過你的函數再處理分隔字元為空白時會有問題
因為很多情況資料欄位間的空白,不是只有一個
可能是兩個欄位間隔了3,4個空白
而此時只能算兩個欄位,不能因為用了3個空白就判斷有4個欄位
例: String *a=Split2(" 2 88 789 36 78,",' ');
答案應該是 a[0]=2 a[1]=88 a[2]=789 ......
用您的程式會結果會有問題 而我的程式有'~'限制, 就是專門用來處理空白分隔符號的
它將連續空白中的第一個空白,以 '~' 取代
以下再以 '~' 作分隔符號, 來區分欄位
------
engineer |
kagaya
中階會員 發表:74 回覆:175 積分:59 註冊:2002-12-28 發送簡訊給我 |
|
kagaya
中階會員 發表:74 回覆:175 積分:59 註冊:2002-12-28 發送簡訊給我 |
|
l8939_c
一般會員 發表:9 回覆:15 積分:4 註冊:2005-03-07 發送簡訊給我 |
kagaya 你好, 你的程式處理 String s1="2 88 789 36 78"; 的確正常 但請將中間分隔"空白"符號改為不一定是一個 例如 : 2 的前面留 2 個空白
2 和 88 中間留 3 個空白
88 和 789 中間留 3 個空白
......... 以此類推 以肉眼來看,連續空白與單一空白一樣, 只會分隔兩筆資料
麻煩你執行看看, 結果是否正常 另外, sizeof(s2)/sizeof(s2[0]) 的問題
由於我們宣告的是指標(*),所以即使元素的長度一樣, 也沒用
我將我的函數做了一點變動, 傳回的陣列,第0個元素即為陣列數目
我想大概就只能做到這樣了吧
用法 :
String *aaa=Split(" 2 88 789 36 78 ,",' ');
for (int i=1;i<=aaa[0].ToInt();i++){
List1->Items->Add(aaa[i]);
} 程式碼如下 : String *Split(String s1,char k1) // 字串分割
{
if (k1==' ') {
String s3;s3=s1.Trim();
for (int i=2;i
------
engineer |
kagaya
中階會員 發表:74 回覆:175 積分:59 註冊:2002-12-28 發送簡訊給我 |
|
kagaya
中階會員 發表:74 回覆:175 積分:59 註冊:2002-12-28 發送簡訊給我 |
|
supman
尊榮會員 發表:29 回覆:770 積分:924 註冊:2002-04-22 發送簡訊給我 |
您好:
剛剛解答另一題,弄了一各偷懶的切割法,您參考參考.
void __fastcall TForm1::Button1Click(TObject *Sender) { TStringList *List; List=new TStringList; AnsiString S="1,,,,,,,2";//不管你中間有幾各關鍵字,他都識為只有兩各元素 S=StringReplace(S,",","\r\n",TReplaceFlags()<上面是利用TStringList特性作解析,可以符合您所有的需求,另外小弟的建議是不知道元素,最好是用TStringList來傳,您會減少一些不必要的麻煩. |
RedSnow
版主 發表:79 回覆:1322 積分:845 註冊:2003-12-15 發送簡訊給我 |
原先我也做過類似的 Split 動作,作法上都大同小異,我以自己的作法修改 l8939_c 的範例如下:
String ReString(String ss, char k1) // 重整字串 { String s1; if (k1 == ' ') { s1 = ss.Trim(); // 去除首尾的空白字元 // 下列兩行敘述係將字串內有兩個空白字元之處壓縮成一個, // 做兩次是因為避免資料內有碰到超過兩個以上的單數空白字元, // (如有三個空白字元,第一次壓縮會變成兩個,因此作兩次較為保險) s1 = StringReplace(s1, " ", " ", TReplaceFlags()<上述係因應本篇的討論與簡化自身範例而寫成數個副程式,如果排除前述的基礎,直接修改 l8939_c 範例碼的話,可簡化如下: String *Split(String ss,char k1) // 字串分割 { String s1; if (k1 == ' ') { s1 = ss.Trim(); s1 = StringReplace(s1, " ", " ", TReplaceFlags()<以上做法應該可以解決不定數空白字元的分隔問題,同時也可避開 l8939_c 所提的限制,大家參考一下吧。 |
l8939_c
一般會員 發表:9 回覆:15 積分:4 註冊:2005-03-07 發送簡訊給我 |
RedSnow 您好, 您的程式下半段蠻精簡的,但我測試後發現對於3個空白以上的間隔符號, 仍有問題, 我將您的程式修改如下, 上半段是處理空白間隔符號, 下半段是參考您的寫法, 程式還算精簡, 也可避開 '~' 的限制了
String *Split2(String ss,char k1) // 字串分割 { if (k1==' ') { // 若分隔字元為空白時,先對字串做處理 String s3;ss=ss.Trim(); // 先去除頭尾空白 for (int i=1;i<=ss.Length();i ) { if (ss.SubString(i,1)!=' ') { s3=s3 ss.SubString(i,1); }else{ if (ss.SubString(i-1,1)!= ' ') s3=s3 ss.SubString(i,1); } } ss=s3; } int n1 = 1; // 計算資料總筆數 for (int i=1; i<=ss.Length(); i ) { if (ss.SubString(i, 1) == k1) n1 ; } String *s2 = new String[n1 1];int pos; s2[0]=n1; for (int i=1; i<=n1; i ) { pos = ss.Pos(k1); if(pos == 0){ s2[i] = ss; }else{ s2[i] = ss.SubString(1, pos-1); ss = ss.SubString(pos 1, ss.Length()-1); } } return s2; }用法如下 : String *s2=Split2(" 1 2 3 4 5 ",' '); for (int i=1;i<=s2[0].ToInt();i ){ List1->Items->Add(a9[i]); // s2[0] 是此陣列的最大範圍 }supman 您好 : 您的程式更為精簡,顯然 TStringList 是蠻方便的, 不過您並未處理"多個空白"分隔符號的問題, 因此我將您的程式加了幾行處理"多個空白"分隔符號 TStringList *Split1(String ss,char k1) // 字串分割 { if (k1==' ') { // 若分隔字元為空白時,先對字串做處理 String s3;ss=ss.Trim(); // 先去除頭尾空白 for (int i=1;i<=ss.Length();i ) { if (ss.SubString(i,1)!=' ') { s3=s3 ss.SubString(i,1); }else{ if (ss.SubString(i-1,1)!= ' ') s3=s3 ss.SubString(i,1); } } ss=s3; } TStringList *List; List=new TStringList; ss=StringReplace(ss,k1,"\r\n",TReplaceFlags()<用法如下 : TStringList *s1=Split1("1,2,3,4,5,",','); // 字串分割 for (int i=0;i不過小弟發現仍有一問題, 如上例, 處理 "1,2,3,4,5," 時,以逗號做分隔, 結果應該是有6個欄位,5的後面還有一個空字串才對,但此程式只會輸出5個欄位,最後一個空字串無法察覺, 利用 String 所寫的程式則無此bug, 不知您是否有辦法解決 ?
------
engineer |
RedSnow
版主 發表:79 回覆:1322 積分:845 註冊:2003-12-15 發送簡訊給我 |
l8939_c 您好: 呵呵~不好意思,我老實招了....我在空白數量的計算上有盲點,在此向您及各位看倌致歉,我將原先那段縮減空白字元的敘述修改如下後,應該就正確了:
String *Split(String ss,char k1) { String s1; if (k1 == ' ') { s1 = ss.Trim(); while (s1.Pos(" ") != 0) { // 檢查字串是否含有連續兩個空白字元? s1 = StringReplace(s1, " ", " ", TReplaceFlags()< |
supman
尊榮會員 發表:29 回覆:770 積分:924 註冊:2002-04-22 發送簡訊給我 |
您好:
不曉得您有實際去玩過我那範例嬤?他的確可以處理一個空白以上的問題.
以下我改寫加上範例,您測試看看.
TStringList *CustStr(AnsiString S,AnsiString Key) { TStringList *List; List=new TStringList; S=StringReplace(S,Key,"\r\n",TReplaceFlags()<不過小弟發現仍有一問題, 如上例, 處理 "1,2,3,4,5," 時,以逗號做分隔, 結果應該是有6個欄位,5的後面還有一個空字串才對,但此程式只會輸出5個欄位,最後一個空字串無法察覺, 利用 String 所寫的程式則無此bug, 不知您是否有辦法解決 ? 假如是這樣表示每出現一個關鍵字就要切割一次,那程式就更簡單了 TStringList *CustStr(AnsiString S,AnsiString Key) { TStringList *List; List=new TStringList; if (S.SubString(S.Length(),Key.Length())==Key) S =Key; S=StringReplace(S,Key,"\r\n",TReplaceFlags()<發表人 - supman 於 2005/05/09 20:51:57 |
RedSnow
版主 發表:79 回覆:1322 積分:845 註冊:2003-12-15 發送簡訊給我 |
l8939_c 您好: 我原來自定函數的用途並不需要知道陣列大小 (因為是處理固定數量的資料),因此前面的範例都未考慮傳回陣列數量的處理,如果要考慮前述狀況,那麼很顯然的,使用 TStringList 是較為方便的 (在此不考慮效率問題,僅就便利性而言),那麼依您前篇所言,我將兩者方式融合後,改寫成如下所示,以紅色標示的那一行應該可以解決您前一篇向 supman 提出的問題:
TStringList *Split1(String ss, char k1) { String s1; if (k1 == ' ') { s1 = ss.Trim(); while (s1.Pos(" ") != 0) { s1 = StringReplace(s1, " ", " ", TReplaceFlags()< |
l8939_c
一般會員 發表:9 回覆:15 積分:4 註冊:2005-03-07 發送簡訊給我 |
|
l8939_c
一般會員 發表:9 回覆:15 積分:4 註冊:2005-03-07 發送簡訊給我 |
|
supman
尊榮會員 發表:29 回覆:770 積分:924 註冊:2002-04-22 發送簡訊給我 |
您好:
但是我們最常遇到的"分隔符號"就是逗號或空白
不太董您上面這句話的意思?
請舉例一下傳入什麼資料進去時是無法解析的?然後您要的結果是什麼? 我根據您最後的舉例再弄一各範例
TStringList *CustStr(AnsiString S,AnsiString Key) { TStringList *List; List=new TStringList; if (S.SubString(S.Length(),Key.Length())==Key) S =Key; S=StringReplace(S,Key,"\r\n",TReplaceFlags()<基本上資料結構中與您要分割的關鍵字並存,在原始定義資料時除非是有規則,不然資料的定義就有問題了. 發表人 - supman 於 2005/05/10 19:26:23 |
RedSnow
版主 發表:79 回覆:1322 積分:845 註冊:2003-12-15 發送簡訊給我 |
l8939_c 您好: 以下是我測試時使用的程式碼:
TStringList *Split1(String ss, char k1) { String s1; if (k1 == ' ') { s1 = ss.Trim(); while (s1.Pos(" ") != 0) { s1 = StringReplace(s1, " ", " ", TReplaceFlags()<以下則是以除錯模式執行結果的截圖,截圖編號對應上述程式碼以紅色標示之處: 圖 (1) 顯示出在自定函式中,List 的內容,共有 7 組 "\r\n" 換行符號: 圖 (2) 顯示出在呼叫 Split1() 函式之後,s1 的 Count 數為 7: 圖 (3) 顯示出 s1 內容輸出至 Memo1 後的結果,s1 第 0 與 6 項的字串值均為 NULL: 您參考一下。 發表人 - RedSnow 於 2005/05/10 21:10:46 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |