這幾天學習分析聲音的波形數據,接收到的是十六進位的數據,需要將數據轉換成十進位再繪圖,這個過程涉及到字元串的分割,正好可以促進自己對C#相關知識的學習。說到分割字元串,我首先想到的是Split,但根據本例分割要求無法直接使用,需要進行一些處理。通過比較,我覺得常用於截取字元串的substring函數 ...
這幾天學習分析聲音的波形數據,接收到的是十六進位的數據,需要將數據轉換成十進位再繪圖,這個過程涉及到字元串的分割,正好可以促進自己對C#相關知識的學習。說到分割字元串,我首先想到的是Split,但根據本例分割要求無法直接使用,需要進行一些處理。通過比較,我覺得常用於截取字元串的substring函數可以較方便的解決該問題,故記錄下來方便與大家交流、學習。(相信一定有更好的處理方法,希望各位不吝賜教)
一.該程式的主要目的/功能
原數據如下圖所示(十六進位數據):
原數據4byte表示一個數(即圖中第一個數是7E51,第二個是75BA……),需要將原數據
按指定長度(4byte)分割成新的字元串,然後轉化為十進位的數:
運行界面:
/*左邊文本框是十六進位的原數據,右邊是按長度為4(byte)分割後轉化得到的相應的十進位數*/
二.程式代碼
1 using System; 2 using System.Text; 3 using System.Windows.Forms; 4 using System.IO; 5 using System.Text.RegularExpressions; 6 7 namespace StringOperate 8 { 9 public partial class Form1 : Form 10 { 11 public Form1() 12 { 13 InitializeComponent(); 14 } 15 16 /// <summary> 17 /// 去掉字元串中的空格、回車和換行,然後按指定長度進行分割 18 /// </summary> 19 /// <param name="str">待處理的字元串</param> 20 /// <returns></returns> 21 static string[] strProcess(string str) 22 { 23 string strProcessed; 24 string pass = @"[\t\r\n\s]"; 25 strProcessed = Regex.Replace(str, pass, ""); //去掉、回車、換行、空格 26 int strLength = strProcessed.Length; //統計經處理後的字元長度 27 //判斷待處理的字元串長度是否符合要求,並給出提示 28 if (strLength % 4 != 0) 29 { 30 int absenceNum = 4-strLength % 4; 31 string notification = $"註意:請檢查數據是否完整!\r\n[提示:數據似乎缺少{absenceNum}位數字數符]"; 32 MessageBox.Show(notification, "Tips", MessageBoxButtons.OK, MessageBoxIcon.Information); 33 } 34 int byteLength = strProcessed.Length / 4; //統計分割後字元數組長度,數組中每個元素長度為四個位元組 35 string[] strArrayH = new string[byteLength]; //存放十六進位字元串 36 int[] dateDecimal = new int[byteLength]; //存放轉換後的十進位數據 37 //將字元串分割為長度為4的字元數組 38 for (int i=0;i<(byteLength);i=i+1) 39 { 40 try 41 { 42 strArrayH[i]= strProcessed.Substring(4*i,4);//i-起始位置,4-子串長度 43 } 44 catch (Exception e) 45 { 46 MessageBox.Show(e.ToString(),"異常提示",MessageBoxButtons.OK,MessageBoxIcon.Warning); 47 continue; 48 } 49 } 50 return strArrayH; 51 } 52 53 private void 打開ToolStripMenuItem_Click(object sender, EventArgs e) 54 { 55 string mydate; 56 OpenFileDialog Ofdlg = new OpenFileDialog(); 57 openFileDialog1.Filter = "Word工作簿97-2003(*.doc)|*.doc|txt files (*.txt)|*.txt|All files (*.*)|*.*"; 58 openFileDialog1.FileName = "default"; 59 openFileDialog1.FilterIndex = 2; 60 openFileDialog1.Title = "請選擇待處理的數據文本"; //對話框的標題 61 62 if (openFileDialog1.ShowDialog()==DialogResult.OK) 63 { 64 FileStream myfile = new FileStream(openFileDialog1.FileName,FileMode.Open,FileAccess.Read); 65 //使用System.Text.Encoding.Defaul告訴StreamReader採用目前操作系統的編碼,避免出現亂碼 66 StreamReader SR = new StreamReader(myfile,Encoding.Default); 67 mydate = SR.ReadToEnd(); 68 try 69 { 70 textBox1.Text = mydate; 71 SR.Close(); 72 } 73 catch (Exception ex) 74 { 75 MessageBox.Show("打開文件出錯:" + ex.Message); 76 } 77 } 78 } 79 80 //將文本按指定長度分割 81 private void 分割字元串ToolStripMenuItem_Click(object sender, EventArgs e) 82 { 83 textBox2.Text = ""; 84 string myContentBefore; 85 string[] myContentAfter; 86 myContentBefore = textBox1.Text.Trim(); 87 myContentAfter = strProcess(myContentBefore); 88 int[] dateDecimal = new int[myContentAfter.Length]; 89 for (int i = 0; i < myContentAfter.Length; i++) 90 { 91 try 92 { 93 dateDecimal[i] = Convert.ToInt32(myContentAfter[i], 16); 94 } 95 catch (Exception ex) 96 { 97 MessageBox.Show(ex.ToString(),"提示"); 98 continue; 99 } 100 finally 101 { 102 /* 103 * textBox2.Text = (textBox2.Text + " " + dateDecimal[i].ToString()).Trim(); 104 * textBox2.Text += dateDecimal[i].ToString() + " "; 105 * 當數據較多時,上面兩種給textBox的賦值方式響應較慢,程式可能出現假死 106 * 需要頻繁更新TextBox(追加文本)時,AppendText能夠穩定的即時更新,而且高效 107 */ 108 textBox2.AppendText(dateDecimal[i].ToString()+" "); 109 } 110 } 111 textBox2.Text = textBox2.Text.TrimEnd(); 112 113 } 114 115 //清空textbox1的內容 116 private void 清除text1ToolStripMenuItem_Click(object sender, EventArgs e) 117 { 118 textBox1.Text = ""; 119 } 120 121 //清空textbox2的內容 122 private void 清除text2ToolStripMenuItem_Click(object sender, EventArgs e) 123 { 124 textBox2.Text = ""; 125 } 126 127 private void 保存ToolStripMenuItem_Click(object sender, EventArgs e) 128 { 129 StreamWriter mySteam; 130 SaveFileDialog Sfdlg = new SaveFileDialog(); 131 saveFileDialog1.Filter= " Word文檔97-2003(*.doc)|*.doc|txt files(*.txt)|*.txt|Excel工作簿97-2003(*.xls)|*.xls|All files(*.*)|*.*"; 132 saveFileDialog1.FilterIndex = 2; //設置預設文件類型 133 saveFileDialog1.FileName = "default1"; //設置文件的預設名稱 134 saveFileDialog1.RestoreDirectory = true; //記憶上次打開位置 135 if (saveFileDialog1.ShowDialog()== DialogResult.OK) 136 { 137 mySteam = new StreamWriter(saveFileDialog1.FileName); 138 mySteam.Write(textBox2.Text.Trim()); 139 //使用Flush()方法將所有信息從基礎緩衝區移動到其目標或清除緩衝區,或者同時執行這兩種操作 140 mySteam.Flush(); 141 mySteam.Close(); 142 } 143 } 144 } 145 }View Code
三.涉及的知識點
1.分割字元串——Substring(int startIndex, int length)
由於需要按4個位元組長度來分割字元串,而原數據是每兩個位元組就有一個空格,所以無法直接通過Split方法進行分割。我想到了兩種思路:①去掉第1、3、5、7……個空格以及回車、換行和製表字元,然後使用Split分割字元串;②去掉所有空格、回車、換行和製表符,然後通過迴圈取字元串的子串的方式而達到‘分割’字元串到字元數組的目的。我覺得第二種方法的思路更簡單,所以採用的是第二種方法。(int startIndex——開始截取子串的位置,int length——子字元串的長度)
2.數據訪問——openFileDialog & saveFileDialog
博客園介紹這方面知識的的文章很多,寫的也非常好,這裡就不再贅述。
3.Convert類 ——ToInt32(string,IFormatProvider)
使用指定的區域性特定格式信息,將數字的指定 String 表示形式轉換為等效的 32 位有符號整數。如本例中Convert.ToInt32(string,16)——把十六進位的數字的字元串轉換為效的 32 位有符號整數(十進位)。詳細用法可參考Microsoft官網的.net開發文檔:Convert類,Convert.ToInt32(string,IFormatProvider)方法。
寫得比較匆忙,歡迎大家批評指正。