QQ交流群:110826636

JavaScriptMinifier C#压缩Javascript

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.IO;

/// <summary>
/// 提供压缩 JavaScript 代码的能力。
/// </summary>
public sealed class JavaScriptMinifier
{
    #region 私有字段

    private const int EOF = -1;

    private readonly StringBuilder _JsBuilder;
    private readonly TextReader _JsReader;
    private int _TheA = Convert.ToInt32('\n');
    private int _TheB;
    private int _TheLookahead = EOF;

    #endregion

    #region 构造函数

    /// <summary>
    /// 初始化 <see cref="JavaScriptMinifier"/> 类的新实例。
    /// </summary>
    /// <param name="jsReader">包含要压缩的 JavaScript 代码的 <see cref="TextReader"/>。</param>
    private JavaScriptMinifier(TextReader jsReader)
    {
        if (jsReader == null) throw new ArgumentNullException("jsReader");

        this._JsReader = jsReader;
        this._JsBuilder = new StringBuilder();
    }

    #endregion

    #region 静态方法

    /// <summary>
    /// 压缩指定的 JavaScript 代码。
    /// </summary>
    /// <param name="js">包含要压缩的 JavaScript 代码的 <see cref="StringBuilder"/>。</param>
    /// <returns>返回包含压缩后的 JavaScript 代码的 <see cref="StringBuilder"/>。</returns>
    public static StringBuilder Minify(StringBuilder js) { return Minify(new StringReader(js.ToString())); }

    /// <summary>
    /// 压缩指定的 JavaScript 代码。
    /// </summary>
    /// <param name="jsCode">要压缩的 JavaScript 代码。</param>
    /// <returns>返回包含压缩后的 JavaScript 代码的 <see cref="StringBuilder"/>。</returns>
    public static StringBuilder Minify(string jsCode) { return Minify(new StringReader(jsCode)); }

    /// <summary>
    /// 压缩指定的 JavaScript 代码。
    /// </summary>
    /// <param name="jsReader">包含要压缩的 JavaScript 代码的 <see cref="TextReader"/>。</param>
    /// <returns>返回包含压缩后的 JavaScript 代码的 <see cref="StringBuilder"/>。</returns>
    public static StringBuilder Minify(TextReader jsReader)
    {
        JavaScriptMinifier jsmin = new JavaScriptMinifier(jsReader);

        jsmin._Jsmin();

        return jsmin._JsBuilder;
    }

    #endregion

    #region 私有方法

    private void _Jsmin()
    {
        this._Action(3);

        while (this._TheA != EOF)
        {
            switch ((Char)this._TheA)
            {
                case ' ':
                    if (_IsAlphanum(this._TheB)) this._Action(1);
                    else this._Action(2);

                    break;
                case '\n':
                    switch ((Char)this._TheB)
                    {
                        case '{':
                        case '[':
                        case '(':
                        case '+':
                        case '-':
                            this._Action(1);

                            break;
                        case ' ':
                            this._Action(3);

                            break;
                        default:
                            if (_IsAlphanum(this._TheB)) this._Action(1);
                            else this._Action(2);

                            break;
                    }

                    break;
                default:
                    switch ((Char)this._TheB)
                    {
                        case ' ':
                            if (_IsAlphanum(this._TheA))
                            {
                                this._Action(1);

                                break;
                            }

                            this._Action(3);

                            break;
                        case '\n':
                            switch ((Char)this._TheA)
                            {
                                case '}':
                                case ']':
                                case ')':
                                case '+':
                                case '-':
                                case '"':
                                case '\'':
                                    this._Action(1);

                                    break;
                                default:
                                    if (_IsAlphanum(this._TheA)) this._Action(1);
                                    else this._Action(3);

                                    break;
                            }

                            break;
                        default:
                            this._Action(1);

                            break;
                    }

                    break;
            }
        }
    }

    private void _Action(int d)
    {
        if (d <= 1) this._Put(this._TheA);
        if (d <= 2)
        {
            this._TheA = this._TheB;

            if (this._TheA == '\'' || this._TheA == '"')
            {
                for (; ; )
                {
                    this._Put(this._TheA);
                    this._TheA = this._Get();

                    if (this._TheA == this._TheB) break;
                    if (this._TheA <= '\n') throw new Exception(string.Format("Error: JSMIN unterminated string literal: {0}", this._TheA));
                    if (this._TheA != '\\') continue;

                    this._Put(this._TheA);
                    this._TheA = this._Get();
                }
            }
        }

        if (d > 3) return;

        this._TheB = this._Next();

        if (this._TheB != '/' || ((((((((((((this._TheA != '(' && this._TheA != ',') && this._TheA != '=') && this._TheA != '[') && this._TheA != '!') && this._TheA != ':') && this._TheA != '&') && this._TheA != '|') && this._TheA != '?') && this._TheA != '{') && this._TheA != '}') && this._TheA != ';') && this._TheA != '\n')) return;

        this._Put(this._TheA);
        this._Put(this._TheB);

        for (; ; )
        {
            this._TheA = this._Get();

            if (this._TheA == '/') break;

            if (this._TheA == '\\')
            {
                this._Put(this._TheA);
                this._TheA = this._Get();
            }
            else if (this._TheA <= '\n') throw new Exception(string.Format("Error: JSMIN unterminated Regular Expression literal : {0}.", this._TheA));

            this._Put(this._TheA);
        }

        this._TheB = this._Next();
    }

    private int _Next()
    {
        int c = this._Get();
        const int s = (int)'*';

        if (c == '/')
        {
            switch ((Char)this._Peek())
            {
                case '/':
                    for (; ; )
                    {
                        c = this._Get();

                        if (c <= '\n') return c;
                    }
                case '*':
                    this._Get();

                    for (; ; )
                    {
                        switch (this._Get())
                        {
                            case s:
                                if (this._Peek() == '/')
                                {
                                    this._Get();

                                    return Convert.ToInt32(' ');
                                }

                                break;
                            case EOF:
                                throw new Exception("Error: JSMIN Unterminated comment.");
                        }
                    }
                default:
                    return c;
            }
        }

        return c;
    }

    private int _Peek()
    {
        this._TheLookahead = this._Get();

        return this._TheLookahead;
    }

    private int _Get()
    {
        int c = this._TheLookahead;
        this._TheLookahead = EOF;

        if (c == EOF) c = this._JsReader.Read();

        return c >= ' ' || c == '\n' || c == EOF ? c : (c == '\r' ? '\n' : ' ');
    }

    private void _Put(int c) { this._JsBuilder.Append((char)c); }

    private static bool _IsAlphanum(int c) { return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' || c > 126); }

    #endregion
}

 JavaScriptMinifier

posted @ 2016-02-02 11:53  FourOne  阅读(1027)  评论(0编辑  收藏  举报