目前分類:C# (4)

瀏覽方式: 標題列表 簡短摘要

最近有個格式化字串的需求,是要計算已知字串的 Byte 數量,每 100 個 Byte 加上一個換行符號(不能超過100)。一開始的想法是一個 char 一個 char 去跑迴圈並計算 Byte 數。不過這樣又似乎不太妥當,想來想去,最後寫成這個樣子:

public static string SetupType(string text) {
//先去除換行字元
text = text.Replace("\r", "").Replace("\n", "");

//每行最大 Byte 數
int bytesCountEachLine = 100;

//記錄目前已處理完成的字元數
int charIndex = 0;

//最後的回傳值
string result = string.Empty;

Encoding ansi
= Encoding.Default;
byte[] textBytes = ansi.GetBytes(text);

while (charIndex < text.Length) {
//起始位置
int start = ansi.GetByteCount(text.Substring(0, charIndex)) ;

//利用 Encoding.GetCharCount 從起始位置將 100 個 Bytes 的字元一次取出
int count = 0;

if (textBytes.Length - start > bytesCountEachLine)
count
= ansi.GetCharCount(textBytes, start, bytesCountEachLine);
else
count
= ansi.GetCharCount(textBytes, start, textBytes.Length - start);

string target = text.Substring(charIndex, count);

//取出來的字串可能會大於 100 Bytes,所以需要把多餘的去掉
while (ansi.GetByteCount(target) > bytesCountEachLine) {
target
= target.Substring(0, target.Length - 1);
count
-= 1;
}

charIndex
+= count;


//最後一行不用加斷行符號
if (charIndex < text.Length)
result
+= target + "\r\n";
else
result
+= target;
}

return result;
}
 
 
用一段以前很愛看的小說片段來測試,結果如下:
測試前:
image 
 
 
測試後:
image 

AnferneeHardaway 發表在 痞客邦 留言(0) 人氣()

剛剛看到天才少年 laneser 寫了一段程式碼,為方便說明,我稍微刪掉了一些。大致上如下:

[STAThread]
static unsafe void Main() {
string s = "123";

fixed (char* ps = s) {
ps[
0] = '3';
ps[
1] = '2';
ps[
2] = '1';
}

MessageBox.Show(
"123");
}

 

 

 

得到的結果是這樣 

image

  

 

呵~很有趣吧!其實原理不難,主要是因為 .NET 的 String 型別是不可變動的 (Immutable),因此為了節省記憶體的使用,CLR 會建立一個保留集區 (Intern Pool) 來存放字串。當程式中使用字串時,CLR會先檢查保留集區,有的話就傳回保留集區內的參考;沒有的話,就把字串加到保留集區內,再傳回參考。

 

 

所以上述程式碼其實是這樣執行的:


image

 

 

  

 

天才少年的這段程式碼實在太有趣了!

AnferneeHardaway 發表在 痞客邦 留言(1) 人氣()

    網友問了個問題,我天真的認為是UrlEncode()就可以解決,直到心冷大指點後,才知道事情不是我想的那麼簡單。經過測試後,不管用什麼方法都沒辦法正確的用WebClient去抓資料,google了老半天也找不到有用的資訊。結果無意中發現這篇,看來跟這個名為punycode的東西有關,有了關鍵字,呵~~人生就變彩色的了,一下子就找到有用的文章。

    看起來是因為大多數的 DNS 伺服器僅支援 ASCII 字元,所以用中文字下去解析時就會發生錯誤,因此才出現punycode這個東西。以下是google到的解法

 

1.自己將中文轉成punycode

   1: public partial class Form1 : Form {
   2:     public Form1() {
   3:         InitializeComponent();
   4:     }
   5:  
   6:     private void Form1_Load(object sender, EventArgs e) {
   7:         string strPunycode = "http://xn--" + Punycode.encode("正負2度c") + ".tw/";
   8:         WebClient client = new WebClient();
   9:         string html = client.DownloadString(strPunycode);
  10:     }
  11: }
  12:  
  13: class Punycode {
  14:     /* Punycode parameters */
  15:     static int TMIN = 1;
  16:     static int TMAX = 26;
  17:     static int BASE = 36;
  18:     static int INITIAL_N = 128;
  19:     static int INITIAL_BIAS = 72;
  20:     static int DAMP = 700;
  21:     static int SKEW = 38;
  22:     static char DELIMITER = '-';
  23:     /**
  24:      * Punycodes a unicode string.
  25:      *
  26:      * @param input Unicode string.
  27:      * @return Punycoded string.
  28:      */
  29:     public static String encode(String input) {
  30:         int n = INITIAL_N;
  31:         int delta = 0;
  32:         int bias = INITIAL_BIAS;
  33:         StringBuilder output = new StringBuilder();
  34:         // Copy all basic code points to the output
  35:         int b = 0;
  36:         for (int i = 0; i < input.Length; i++) {
  37:             char c = input[i];
  38:             if (isBasic(c)) {
  39:                 output.Append(c);
  40:                 b++;
  41:             }
  42:         }
  43:         // Append delimiter
  44:         if (b > 0) {
  45:             output.Append(DELIMITER);
  46:         }
  47:         int h = b;
  48:         while (h < input.Length) {
  49:             int m = int.MaxValue;
  50:             // Find the minimum code point >= n
  51:             for (int i = 0; i < input.Length; i++) {
  52:                 int c = input[i];
  53:                 if (c >= n && c < m) {
  54:                     m = c;
  55:                 }
  56:             }
  57:             if (m - n > (int.MaxValue - delta) / (h + 1)) {
  58:                 throw new Exception("OVERFLOW");
  59:             }
  60:             delta = delta + (m - n) * (h + 1);
  61:             n = m;
  62:             for (int j = 0; j < input.Length; j++) {
  63:                 int c = input[j];
  64:                 if (c < n) {
  65:                     delta++;
  66:                     if (0 == delta) {
  67:                         throw new Exception("OVERFLOW");
  68:                     }
  69:                 }
  70:                 if (c == n) {
  71:                     int q = delta;
  72:                     for (int k = BASE; ; k += BASE) {
  73:                         int t;
  74:                         if (k <= bias) {
  75:                             t = TMIN;
  76:                         } else if (k >= bias + TMAX) {
  77:                             t = TMAX;
  78:                         } else {
  79:                             t = k - bias;
  80:                         }
  81:                         if (q < t) {
  82:                             break;
  83:                         }
  84:                         output.Append((char)digit2codepoint(t + (q - t) % (BASE - t)));
  85:                         q = (q - t) / (BASE - t);
  86:                     }
  87:                     output.Append((char)digit2codepoint(q));
  88:                     bias = adapt(delta, h + 1, h == b);
  89:                     delta = 0;
  90:                     h++;
  91:                 }
  92:             }
  93:             delta++;
  94:             n++;
  95:         }
  96:         return output.ToString();
  97:     }
  98:     /**
  99:      * Decode a punycoded string.
 100:      *
 101:      * @param input Punycode string
 102:      * @return Unicode string.
 103:      */
 104:     public static String decode(String input) {
 105:         int n = INITIAL_N;
 106:         int i = 0;
 107:         int bias = INITIAL_BIAS;
 108:         StringBuilder output = new StringBuilder();
 109:         int d = input.LastIndexOf(DELIMITER);
 110:         if (d > 0) {
 111:             for (int j = 0; j < d; j++) {
 112:                 char c = input[j];
 113:                 if (!isBasic(c)) {
 114:                     throw new Exception("BAD_INPUT");
 115:                 }
 116:                 output.Append(c);
 117:             }
 118:             d++;
 119:         } else {
 120:             d = 0;
 121:         }
 122:         while (d < input.Length) {
 123:             int oldi = i;
 124:             int w = 1;
 125:             for (int k = BASE; ; k += BASE) {
 126:                 if (d == input.Length) {
 127:                     throw new Exception("BAD_INPUT");
 128:                 }
 129:                 int c = input[d++];
 130:                 int digit = codepoint2digit(c);
 131:                 if (digit > (int.MaxValue - i) / w) {
 132:                     throw new Exception("OVERFLOW");
 133:                 }
 134:                 i = i + digit * w;
 135:                 int t;
 136:                 if (k <= bias) {
 137:                     t = TMIN;
 138:                 } else if (k >= bias + TMAX) {
 139:                     t = TMAX;
 140:                 } else {
 141:                     t = k - bias;
 142:                 }
 143:                 if (digit < t) {
 144:                     break;
 145:                 }
 146:                 w = w * (BASE - t);
 147:             }
 148:             bias = adapt(i - oldi, output.Length + 1, oldi == 0);
 149:             if (i / (output.Length + 1) > int.MaxValue - n) {
 150:                 throw new Exception("OVERFLOW");
 151:             }
 152:             n = n + i / (output.Length + 1);
 153:             i = i % (output.Length + 1);
 154:             output.Insert(i, (char)n);
 155:             i++;
 156:         }
 157:         return output.ToString();
 158:     }
 159:     public static int adapt(int delta, int numpoints, bool first) {
 160:         if (first) {
 161:             delta = delta / DAMP;
 162:         } else {
 163:             delta = delta / 2;
 164:         }
 165:         delta = delta + (delta / numpoints);
 166:         int k = 0;
 167:         while (delta > ((BASE - TMIN) * TMAX) / 2) {
 168:             delta = delta / (BASE - TMIN);
 169:             k = k + BASE;
 170:         }
 171:         return k + ((BASE - TMIN + 1) * delta) / (delta + SKEW);
 172:     }
 173:     public static bool isBasic(char c) {
 174:         return c < 0x80;
 175:     }
 176:     public static int digit2codepoint(int d) {
 177:         if (d < 26) {
 178:             // 0..25 : 'a'..'z'
 179:             return d + 'a';
 180:         } else if (d < 36) {
 181:             // 26..35 : '0'..'9';
 182:             return d - 26 + '0';
 183:         } else {
 184:             throw new Exception("BAD_INPUT");
 185:         }
 186:     }
 187:     public static int codepoint2digit(int c) {
 188:         if (c - '0' < 10) {
 189:             // '0'..'9' : 26..35
 190:             return c - '0' + 26;
 191:         } else if (c - 'a' < 26) {
 192:             // 'a'..'z' : 0..25
 193:             return c - 'a';
 194:         } else {
 195:             throw new Exception("BAD_INPUT");
 196:         }
 197:     }
 198: }

 

  2.直接使用config檔的設定

.在C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config加入這一段


   1: <section name="uri" type="System.Configuration.UriSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />

 

.在app.config中加入


   1: <configuration>
   2:   <uri>
   3:   <idn enabled="All" />
   4:   <iriParsing enabled="true" />
   5:   </uri>
   6: </configuration>

 

 

然後程式碼完全不用動


   1: public partial class Form1 : Form {
   2:     public Form1() {
   3:         InitializeComponent();
   4:     }
   5:  
   6:     private void Form1_Load(object sender, EventArgs e) {
   7:         string url = "http://正負2度c.tw/";
   8:         WebClient client = new WebClient();
   9:         string html = client.DownloadString(url);
  10:     }
  11: }

 

 

 

 

 

以上就屬第二種最方便,也說明了.NET真的是好用到一個不行啊~~

AnferneeHardaway 發表在 痞客邦 留言(0) 人氣()

同事問了一個問題:

      假如有兩個物件(A和B),這兩個物件分屬不同類別,且大多數的屬性都一樣,但彼此沒有繼承關係,也不能修改原始類別的程式碼。要如何快速將物件A的屬性值全部複製給物件B??

思考了一下,由於功力不深,所以只想得出PropertyInfo類別。

 

首先定義ClassA及ClassB

public class ClassA {
    public string Str1 { get; set; }
    public string Str2 { get; set; }
    public string Str3 { get; set; }
    public string Str4 { get; set; }
    public string Str5 { get; set; }
    public string Str6 { get; set; }
    public string Str7 { get; set; }
    public string Str8 { get; set; }
    public string Str9 { get; set; }
    public string Str10 { get; set; }
    public string Str11 { get; set; }
    public string Str12 { get; set; }
    public string Str13 { get; set; }
    public string Str14 { get; set; }
    public string Str15 { get; set; }
    public string Str16 { get; set; }
    public string Str17 { get; set; }
    public string Str18 { get; set; }
    public string Str19 { get; set; }
    public string Str20 { get; set; }
    public string Str21 { get; set; }
    public string Str22 { get; set; }
    public string Str23 { get; set; }
    public string Str24 { get; set; }
    public string Str25 { get; set; }
    public string Str26 { get; set; }
    public string Str27 { get; set; }
    public string Str28 { get; set; }
    public string Str29 { get; set; }
    public string Str30 { get; set; }
    public string Str31 { get; set; }
    public string Str32 { get; set; }
    public string Str33 { get; set; }
    public string Str34 { get; set; }
    public string Str35 { get; set; }
    public string Str36 { get; set; }
    public string Str37 { get; set; }
    public string Str38 { get; set; }
    public string Str39 { get; set; }
    public string Str40 { get; set; }
    public string Str41 { get; set; }
    public string Str42 { get; set; }
    public string Str43 { get; set; }
    public string Str44 { get; set; }
    public string Str45 { get; set; }
    public string Str46 { get; set; }
    public string Str47 { get; set; }
    public string Str48 { get; set; }
    public string Str49 { get; set; }
    public string Str50 { get; set; }
    public string Str51 { get; set; }
    public string Str52 { get; set; }
    public string Str53 { get; set; }
    public string Str54 { get; set; }
    public string Str55 { get; set; }
    public string Str56 { get; set; }
    public string Str57 { get; set; }
    public string Str58 { get; set; }
    public string Str59 { get; set; }
    public string Str60 { get; set; }
    public string Str61 { get; set; }
    public string Str62 { get; set; }
    public string Str63 { get; set; }
    public string Str64 { get; set; }
    public string Str65 { get; set; }
    public string Str66 { get; set; }
    public string Str67 { get; set; }
    public string Str68 { get; set; }
    public string Str69 { get; set; }
    public string Str70 { get; set; }
    public string Str71 { get; set; }
    public string Str72 { get; set; }
    public string Str73 { get; set; }
    public string Str74 { get; set; }
    public string Str75 { get; set; }
    public string Str76 { get; set; }
    public string Str77 { get; set; }
    public string Str78 { get; set; }
    public string Str79 { get; set; }
    public string Str80 { get; set; }
    public string Str81 { get; set; }
    public string Str82 { get; set; }
    public string Str83 { get; set; }
    public string Str84 { get; set; }
    public string Str85 { get; set; }
    public string Str86 { get; set; }
    public string Str87 { get; set; }
    public string Str88 { get; set; }
    public string Str89 { get; set; }
    public string Str90 { get; set; }
    public string Str91 { get; set; }
    public string Str92 { get; set; }
    public string Str93 { get; set; }
    public string Str94 { get; set; }
    public string Str95 { get; set; }
    public string Str96 { get; set; }
    public string Str97 { get; set; }
    public string Str98 { get; set; }
    public string Str99 { get; set; }
    public string Str100 { get; set; }
}
 
public class ClassB {
    public string Str1 { get; set; }
    public string Str2 { get; set; }
    public string Str3 { get; set; }
    public string Str4 { get; set; }
    public string Str5 { get; set; }
    public string Str6 { get; set; }
    public string Str7 { get; set; }
    public string Str8 { get; set; }
    public string Str9 { get; set; }
    public string Str10 { get; set; }
    public string Str11 { get; set; }
    public string Str12 { get; set; }
    public string Str13 { get; set; }
    public string Str14 { get; set; }
    public string Str15 { get; set; }
    public string Str16 { get; set; }
    public string Str17 { get; set; }
    public string Str18 { get; set; }
    public string Str19 { get; set; }
    public string Str20 { get; set; }
    public string Str21 { get; set; }
    public string Str22 { get; set; }
    public string Str23 { get; set; }
    public string Str24 { get; set; }
    public string Str25 { get; set; }
    public string Str26 { get; set; }
    public string Str27 { get; set; }
    public string Str28 { get; set; }
    public string Str29 { get; set; }
    public string Str30 { get; set; }
    public string Str31 { get; set; }
    public string Str32 { get; set; }
    public string Str33 { get; set; }
    public string Str34 { get; set; }
    public string Str35 { get; set; }
    public string Str36 { get; set; }
    public string Str37 { get; set; }
    public string Str38 { get; set; }
    public string Str39 { get; set; }
    public string Str40 { get; set; }
    public string Str41 { get; set; }
    public string Str42 { get; set; }
    public string Str43 { get; set; }
    public string Str44 { get; set; }
    public string Str45 { get; set; }
    public string Str46 { get; set; }
    public string Str47 { get; set; }
    public string Str48 { get; set; }
    public string Str49 { get; set; }
    public string Str50 { get; set; }
    public string Str51 { get; set; }
    public string Str52 { get; set; }
    public string Str53 { get; set; }
    public string Str54 { get; set; }
    public string Str55 { get; set; }
    public string Str56 { get; set; }
    public string Str57 { get; set; }
    public string Str58 { get; set; }
    public string Str59 { get; set; }
    public string Str60 { get; set; }
    public string Str61 { get; set; }
    public string Str62 { get; set; }
    public string Str63 { get; set; }
    public string Str64 { get; set; }
    public string Str65 { get; set; }
    public string Str66 { get; set; }
    public string Str67 { get; set; }
    public string Str68 { get; set; }
    public string Str69 { get; set; }
    public string Str70 { get; set; }
    public string Str71 { get; set; }
    public string Str72 { get; set; }
    public string Str73 { get; set; }
    public string Str74 { get; set; }
    public string Str75 { get; set; }
    public string Str76 { get; set; }
    public string Str77 { get; set; }
    public string Str78 { get; set; }
    public string Str79 { get; set; }
    public string Str80 { get; set; }
    public string Str81 { get; set; }
    public string Str82 { get; set; }
    public string Str83 { get; set; }
    public string Str84 { get; set; }
    public string Str85 { get; set; }
    public string Str86 { get; set; }
    public string Str87 { get; set; }
    public string Str88 { get; set; }
    public string Str89 { get; set; }
    public string Str90 { get; set; }
 
    public int Str91 { get; set; }
    public int Str92 { get; set; }
    public int Str93 { get; set; }
    public int Str94 { get; set; }
    public int Str95 { get; set; }
    public int Str96 { get; set; }
    public int Str97 { get; set; }
    public int Str98 { get; set; }
    public int Str99 { get; set; }
    public int Str100 { get; set; }
}

 

 

 

接著產生物件A、物件B


ClassA a = new ClassA() {
            Str1 = "Str1",
            Str2 = "Str2",
            Str3 = "Str3",
            Str4 = "Str4",
            Str5 = "Str5",
            Str6 = "Str6",
            Str7 = "Str7",
            Str8 = "Str8",
            Str9 = "Str9",
            Str10 = "Str10",
            Str11 = "Str11",
            Str12 = "Str12",
            Str13 = "Str13",
            Str14 = "Str14",
            Str15 = "Str15",
            Str16 = "Str16",
            Str17 = "Str17",
            Str18 = "Str18",
            Str19 = "Str19",
            Str20 = "Str20",
            Str21 = "Str21",
            Str22 = "Str22",
            Str23 = "Str23",
            Str24 = "Str24",
            Str25 = "Str25",
            Str26 = "Str26",
            Str27 = "Str27",
            Str28 = "Str28",
            Str29 = "Str29",
            Str30 = "Str30",
            Str31 = "Str31",
            Str32 = "Str32",
            Str33 = "Str33",
            Str34 = "Str34",
            Str35 = "Str35",
            Str36 = "Str36",
            Str37 = "Str37",
            Str38 = "Str38",
            Str39 = "Str39",
            Str40 = "Str40",
            Str41 = "Str41",
            Str42 = "Str42",
            Str43 = "Str43",
            Str44 = "Str44",
            Str45 = "Str45",
            Str46 = "Str46",
            Str47 = "Str47",
            Str48 = "Str48",
            Str49 = "Str49",
            Str50 = "Str50",
            Str51 = "Str51",
            Str52 = "Str52",
            Str53 = "Str53",
            Str54 = "Str54",
            Str55 = "Str55",
            Str56 = "Str56",
            Str57 = "Str57",
            Str58 = "Str58",
            Str59 = "Str59",
            Str60 = "Str60",
            Str61 = "Str61",
            Str62 = "Str62",
            Str63 = "Str63",
            Str64 = "Str64",
            Str65 = "Str65",
            Str66 = "Str66",
            Str67 = "Str67",
            Str68 = "Str68",
            Str69 = "Str69",
            Str70 = "Str70",
            Str71 = "Str71",
            Str72 = "Str72",
            Str73 = "Str73",
            Str74 = "Str74",
            Str75 = "Str75",
            Str76 = "Str76",
            Str77 = "Str77",
            Str78 = "Str78",
            Str79 = "Str79",
            Str80 = "Str80",
            Str81 = "Str81",
            Str82 = "Str82",
            Str83 = "Str83",
            Str84 = "Str84",
            Str85 = "Str85",
            Str86 = "Str86",
            Str87 = "Str87",
            Str88 = "Str88",
            Str89 = "Str89",
            Str90 = "Str90",
            Str91 = "Str91",
            Str92 = "Str92",
            Str93 = "Str93",
            Str94 = "Str94",
            Str95 = "Str95",
            Str96 = "Str96",
            Str97 = "Str97",
            Str98 = "Str98",
            Str99 = "Str99",
            Str100 = "Str100"
        };
 
        ClassB b = new ClassB();

 

 

 

最後就是複製的動作了


Type typeB = typeof(ClassB);
PropertyInfo[] propertiesA = typeof(ClassA).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo infoA in propertiesA) {
    string name = infoA.Name;
    PropertyInfo infoB = typeB.GetProperty(name, BindingFlags.Public | BindingFlags.Instance);
    if (infoB != null && infoA.PropertyType == infoB.PropertyType) {
        infoB.SetValue(b, infoA.GetValue(a, null), null);
    }
}

 

 

 

結果

Copy_Properties

 

其實Reflection命名空間還蠻神奇的,它甚至連物件內的private變數也能進行修改。只是一直沒時間好好研究它......

AnferneeHardaway 發表在 痞客邦 留言(0) 人氣()