2014-02-05 20:53

[C#] HttpUtility.ParseQueryString 的隱藏密技

在使用 Request.QueryString 發現 ToString 會產生 URL 的 query 字串,嘗試用 NameValueCollection 的 ToString 卻不是產生 URL 的 query 字串,這一整個就很奇怪,明明都是 NameValueCollection 確有不一樣的結果,透過 Reflector 發現 Request.QueryString 的 instance 型別是一個 HttpValueCollection,想說可以直接 new HttpValueCollection 出來使用,但 HttpValueCollection 卻是 System.Web 的內部 Class,外部是無法直接 new 出來使用,還好在又發現 HttpUtility.ParseQueryString 回傳的 NameValueCollection 的 instance 是 HttpValueCollection 這個型別,所以可以透過 HttpUtility.ParseQueryString 來建立 HttpValueCollection。

// using System.Web;

var qs1 = HttpUtility.ParseQueryString("id=5&type=1");
qs1.ToString(); // "id=5&type=1"

var qs2 = HttpUtility.ParseQueryString(String.Empty);
qs2["id"] = "11";
qs2["name"] = "Tom"; 

qs2.ToString(); // "id=11&name=Tom"


HttpValueCollection 的簽名
[Serializable]     
internal class HttpValueCollection : NameValueCollection     
{
}


ParseQueryString 的簽名
public static NameValueCollection ParseQueryString(string query, Encoding encoding)
{
    if (query == null)
    {
        throw new ArgumentNullException("query");
    }
    if (encoding == null)
    {
        throw new ArgumentNullException("encoding");
    }
    if ((query.Length > 0) && (query[0] == '?'))
    {
        query = query.Substring(1);
    }
    return new HttpValueCollection(query, false, true, encoding);
}
2014-02-05 20:25

[CSS] float 與 clear

float

一開始是用來定義文繞圖的呈現,後來其浮動特性很適合用來排版佈局,所以大部分的網頁都用這種方式排版。

特性:
  • 不佔用父元素的空間
  • 寬高會內縮至子元素所呈現的大小
  • 會排擠其他相鄰的 inline 元素
  • 在所定位的空間不足時會自動換行

<div style="border:1px solid #f00; float:left;">div 1</div>
<div style="background:#0f0;">div 2</div>
div1
div2

透過上面的範例可以看出因為 div1 不佔用空間而讓 div2 的位子上移了,然而呈現與 div1 重疊的效果,以及可以看到 float 排擠文字的特性,而讓 div2 的文字被擠到 div1 之後。



clear

清除在元素相鄰邊上的 float 元素

屬性:
  • none 不做任何 clear 動作
  • left 將元素向下換行,來排除具有 float:left 的相鄰元素
  • right 將元素向下換行,來排除具有 float:right 的相鄰元素
  • both 將元素向下換行,來排除具有 float:left 或 float:right 的相鄰元素

<div style="border:1px solid #f00; float:left;">div1</div>
<div style="background:#0f0; clear:left;">div2</div>
div1
div2

這個範例在 div2 加上 clear:left 的屬性,讓 div2 根據前一個具有 float:left 元素之後向下換行,來排除具有 float:left 的相鄰元素。


<div style="border:1px solid #f00; float:left;">div1</div>
<div style="background:#0f0; clear:right;">div2</div>
div1
div2

這個範例則是將 div2 換成 clear:right,可以看到 div1 與 div2 仍舊重疊在一起,這是因為 div2 前一個具有 float:right 不存在,而 div1 的 float:left 不是 div2 clear:right 排除的對象。
2014-01-30 20:46

[CSS] display inline, block 與 inline-block

inline 行內 (例如: <b>,<span>),具有以下特性:
  • 會連接在文字及 inline 元素之後
  • 不具有 width, height 以及上下的 padding, margin (padding-top, padding-bottom, margin-top, margin-bottom)
  • 寬度、高度會內縮至所含文字所使用的空間

block 區塊 (例如: <p>,<div>),具有以下特性:
  • 會獨佔父元素一整行的空間
  • 具有完整 width, height 及 padding, margin 屬性
  • 當不指定寬度時,預設寬度會擴張至一整列
  • 當不指定高度時,預設高度會內縮至子元素所使用的空間

inline-block 行內-區塊 (例如: <img>,<button>),同時具備 inline 與 block 的特性:
  • 會連接在文字及 inline 元素之後
  • 具有完整 width, height 及 padding, margin 屬性
  • 當不指定寬度、高度時,預設會內縮至所含文字所使用的空間
2014-01-30 20:41

[CSS] Selector Meaning

SelectorMeaning
ABA and B
A, BA or B
A Bforeach B whose parents contains A
A > Bforeach B whose parent is A
A + Bforeach B whose previous sibling is A
A ~ Bforeach B whose previous siblings contains A
2014-01-30 20:33

[C#] 圖片縮圖

System.Drawing namespace 提供對 GDI+ 基本繪圖功能的存取,可以方便處理圖片的操作,下面是一個處理圖片縮圖的範例:

//using System.Drawing;

var image = Image.FromFile(@"D:\001.jpg");

int width = 120, height = 100;
float targetRatio = (float)width / (float)height;
float imageRatio = (float)image.Width / (float)image.Height;


if(imageRatio < targetRatio)
{
    width = Math.Max(1, height * image.Width / image.Height);
}
else
{
    height = Math.Max(1, width * image.Height / image.Width); 
}


var thumbnail = image.GetThumbnailImage(width, height, null, IntPtr.Zero);

thumbnail.Save(@"D:\thumb.jpg");

這個方式可以容易的做到圖片縮圖,但使用這個方式會很佔用記憶體,在處理尺寸大的圖片時有可能會出現 out of memory,而且在 MSDN 有以下的警示:
Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions. For a supported alternative, see Windows Imaging Components.
2014-01-21 01:02

[JavaScript] 匿名 function 進階應用

前幾天 JS 新手村的同事說看不懂下面的程式,下面用了幾個問句解釋了他的疑惑。
(function(model){
    //...
})(model || model={});

JS 要如何宣告一個 function 呢?
function a(){
    //...
}

那改成變數的方式宣告呢?
var a = function(){
    //...
};

要怎麼呼叫上面宣告的 function?
a();

再來把 a 換成等於右邊的 function 宣告。
function(){
    //...
}();

上面的寫法不符合語法,再加上 () 吧!
(function(){
    //...
})();


接著 model || model={} 是透過 or 判斷句的特性,遇到第一個為真就回傳,看看下面的例子:
var a = 1 || 2 || 3;  // 1
var a = 0 || 2 || 3;  // 2
var a = 0 || 0 || 3;  // 3



為什麼要用這種寫法呢??

首先 JS 沒有所謂的 block 變數,在 for 內宣告的變數,外面也能直接存取,唯一能侷限變數存取域的只有 function,在 function 內宣告的變數只有內部能存取,外部是看不見的,所以透過這個方法可以避免變數命名衝突的問題。

再來透過傳入 function 的變數,外部是無法在更動的,變數的參考點在呼叫 function 就固定下來,外部無法在異動內部所存取的參考點,這樣可以避免參考的變數內容被其他套件程式修改,而造成執行錯誤。
2014-01-21 00:23

[Less] 簡單做到背景漸層

對選顏色不擅長,又想在網頁做出 CSS 漸層效果,Less 提供了兩個方便的函數 lighten(加亮顏色)、darken(加深顏色),透過這兩個函數就可以輕鬆產生漸層所需要的色差,然後調整百比值就可以控制漸層的色階。

.toolbar {
    @color: #914;
    @lighten: lighten(@color, 3%);
    @darken: darken(@color, 3%);

    background-color: @color;
    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@lighten), to(@darken));
    background-image: -webkit-linear-gradient(top, @lighten, @darken);
    background-image: -moz-linear-gradient(top, @lighten, @darken);
    background-image: -ms-linear-gradient(top, @lighten, @darken);
    background-image: -o-linear-gradient(top, @lighten, @darken);
    background-image: linear-gradient(to bottom, @lighten, @darken);
}

上面除了用 linear-gradient 來產生漸層,額外還加上了 background-color 這個保險,讓不支援 CSS3 的 browser 也能有基本的底色。


這樣寫還是有點麻煩,如果包成 mixin 會更方便,如下:
.bg-vertical-gradient(@color, @amount:3%) {
    @lighten: lighten(@color, @amount);
    @darken: darken(@color, @amount);

    background-color: @color;
    background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@lighten), to(@darken));
    background-image: -webkit-linear-gradient(top, @lighten, @darken);
    background-image: -moz-linear-gradient(top, @lighten, @darken);
    background-image: -ms-linear-gradient(top, @lighten, @darken);
    background-image: -o-linear-gradient(top, @lighten, @darken);
    background-image: linear-gradient(to bottom, @lighten, @darken);
}

.toolbar {
    .bg-vertical-gradient(#914);
}

.banner {
    .bg-vertical-gradient(#702, 5%);
}
2013-08-25 16:43

[轉載] 字符串匹配的 Boyer-Moore 演算法

轉載自:字符串匹配的Boyer-Moore算法 - 阮一峰的网络日志

上一篇文章,我介绍了KMP算法

但是,它并不是效率最高的算法,实际采用并不多。各种文本编辑器的"查找"功能(Ctrl+F),大多采用Boyer-Moore算法



Boyer-Moore算法不仅效率高,而且构思巧妙,容易理解。1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore教授发明了这种算法。

下面,我根据Moore教授自己的例子来解释这种算法。


1.



假定字符串为"HERE IS A SIMPLE EXAMPLE",搜索词为"EXAMPLE"。



2.



首先,"字符串"与"搜索词"头部对齐,从尾部开始比较。

这是一个很聪明的想法,因为如果尾部字符不匹配,那么只要一次比较,就可以知道前7个字符(整体上)肯定不是要找的结果。

我们看到,"S"与"E"不匹配。这时,"S"就被称为"坏字符"(bad character),即不匹配的字符。我们还发现,"S"不包含在搜索词"EXAMPLE"之中,这意味着可以把搜索词直接移到"S"的后一位。



3.



依然从尾部开始比较,发现"P"与"E"不匹配,所以"P"是"坏字符"。但是,"P"包含在搜索词"EXAMPLE"之中。所以,将搜索词后移两位,两个"P"对齐。



4.



我们由此总结出"坏字符规则"

后移位数 = 坏字符的位置 - 搜索词中的上一次出现位置

如果"坏字符"不包含在搜索词之中,则上一次出现位置为 -1。

以"P"为例,它作为"坏字符",出现在搜索词的第6位(从0开始编号),在搜索词中的上一次出现位置为4,所以后移 6 - 4 = 2位。再以前面第二步的"S"为例,它出现在第6位,上一次出现位置是 -1(即未出现),则整个搜索词后移 6 - (-1) = 7位。



5.



依然从尾部开始比较,"E"与"E"匹配。



6.



比较前面一位,"LE"与"LE"匹配。



7.



比较前面一位,"PLE"与"PLE"匹配。



8.



比较前面一位,"MPLE"与"MPLE"匹配。我们把这种情况称为"好后缀"(good suffix),即所有尾部匹配的字符串。注意,"MPLE"、"PLE"、"LE"、"E"都是好后缀。



9.



比较前一位,发现"I"与"A"不匹配。所以,"I"是"坏字符"。



10.



根据"坏字符规则",此时搜索词应该后移 2 - (-1)= 3 位。问题是,此时有没有更好的移法?



11.



我们知道,此时存在"好后缀"。所以,可以采用"好后缀规则"

后移位数 = 好后缀的位置 - 搜索词中的上一次出现位置

举例来说,如果字符串"ABCDAB"的后一个"AB"是"好后缀"。那么它的位置是5(从0开始计算,取最后的"B"的值),在"搜索词中的上一次出现位置"是1(第一个"B"的位置),所以后移 5 - 1 = 4位,前一个"AB"移到后一个"AB"的位置。

再举一个例子,如果字符串"ABCDEF"的"EF"是好后缀,则"EF"的位置是5 ,上一次出现的位置是 -1(即未出现),所以后移 5 - (-1) = 6位,即整个字符串移到"F"的后一位。

这个规则有三个注意点:

  1. "好后缀"的位置以最后一个字符为准。假定"ABCDEF"的"EF"是好后缀,则它的位置以"F"为准,即5(从0开始计算)。
  2. 如果"好后缀"在搜索词中只出现一次,则它的上一次出现位置为 -1。比如,"EF"在"ABCDEF"之中只出现一次,则它的上一次出现位置为-1(即未出现)。
  3. 如果"好后缀"有多个,则除了最长的那个"好后缀",其他"好后缀"的上一次出现位置必须在头部。比如,假定"BABCDAB"的"好后缀"是"DAB"、"AB"、"B",请问这时"好后缀"的上一次出现位置是什么?回答是,此时采用的好后缀是"B",它的上一次出现位置是头部,即第0位。这个规则也可以这样表达:如果最长的那个"好后缀"只出现一次,则可以把搜索词改写成如下形式进行位置计算"(DA)BABCDAB",即虚拟加入最前面的"DA"。

回到上文的这个例子。此时,所有的"好后缀"(MPLE、PLE、LE、E)之中,只有"E"在"EXAMPLE"还出现在头部,所以后移 6 - 0 = 6位。



12.



可以看到,"坏字符规则"只能移3位,"好后缀规则"可以移6位。所以,Boyer-Moore算法的基本思想是,每次后移这两个规则之中的较大值。

更巧妙的是,这两个规则的移动位数,只与搜索词有关,与原字符串无关。因此,可以预先计算生成《坏字符规则表》和《好后缀规则表》。使用时,只要查表比较一下就可以了。



13.



继续从尾部开始比较,"P"与"E"不匹配,因此"P"是"坏字符"。根据"坏字符规则",后移 6 - 4 = 2位。



14.



从尾部开始逐位比较,发现全部匹配,于是搜索结束。如果还要继续查找(即找出全部匹配),则根据"好后缀规则",后移 6 - 0 = 6位,即头部的"E"移到尾部的"E"的位置。

(完)