WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

JavaScript で全角数字を半角に変換

by WebSurfer 2017年9月24日 14:12

先の記事「全角数字を半角に変換」は C# のコードで書きましたが、それと同等なコードを JavaScript で実装してみました。

JavaScript で全角数字を半角に変換

JavaScript の String.prototype.replace(), String.fromCharCode(), String.prototype.charCodeAt() の使い方の備忘録ですので、記事としては面白くないと思います。スミマセン(汗)

上記のメソッドを利用して、テキストボックスに全角数字交じりの文字をタイプしてフォーカスを外すと全角数字 ⇒ 半角数字に変換するサンプルを以下に書いておきます。上の画像はその実行結果です。

<%@ Page Language="C#" %>

<!DOCTYPE html>

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
  <title>JavaScript で全角数字 ⇒ 半角数字</title>
  <script src="/Scripts/jquery-1.10.2.js"></script>
  <script type="text/javascript">
  //<![CDATA[
    var zen2han = function(str) {
      str = str.replace(/[0-9]/g, function (s) {
        return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
      })
      return str;
    }

    $(function () {
      $("#text1").on("change", function () {
        var str = $(this).val();
        $(this).val(zen2han(str));
      });
    });
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
    <h2>JavaScript で全角数字 ⇒ 半角数字</h2>
    <p>入力してフォーカスを外すと全角数字 ⇒ 半角数字に変換</p>
    <input id="text1" type="text" style="width: 350px;" />
  </form>
</body>
</html>

テキストボックスの change イベントでの書き換えのコーディングが面倒なので、その部分は jQuery を使ってますが、変換するためのメソッドは上記の JavaScript のメソッドを使っています。

replace メソッドは、第一引数の正規表現 /[0-9]/g にマッチした文字列の一部または全てを、第二引数に指定される文字列で置き換えた新しい文字列を返します。

第二引数には新しい部分文字列を生成するために実行される関数を指定することができます。上の例では匿名関数 function (s) { ... } を使っています。

全角数字の UTF-16 コードから 0xFEE0 を引くと半角数字の UTF-16 コードになるので、匿名関数 function (s) { ... } は JavaScript の charCodeAt メソッドと fromCharCode メソッドを利用して全角数字を半角数字の文字列に変換します。

具体的には (1) charCodeAt メソッドでインデックス 0 に位置する文字の UTF-16 コードを表す整数を取得、(2) それから 0xFEE0 を引いて半角数字の UTF-16 コードを取得、(3) fromCharCode メソッドで指定された UTF-16 値の文字列を取得して戻り値として返しています。

Tags: , ,

JavaScript

for...in ループと hasOwnProperty

by WebSurfer 2017年6月30日 15:38

JavaScript の for...in ループ内で hasOwnProperty を使っているコード例を見かけますが、hasOwnProperty を使うことにどういう意味があるかを書きます。(詳細は後述しますが、下の画像で赤枠が hasOwnProperty を使わない場合、青枠が使った場合の結果です)

hasOwnProperty 有無の違い

MDN (Mozilla Developer Network) の記事「Object.prototype.hasOwnProperty()」に "in 演算子と違って、このメソッドはオブジェクトのプロトタイプチェーンをたどってチェックしません" と書いてあって、for...in ループの中で hasOwnProperty プロパティを使うコード例もありましたが、自分的にはどうもピンときません。

なので、自分的に納得できる具体例を以下に書いておきます。

マイクロソフト公式解説書「プログラミング Microsoft ASP.NET MVC」の 10.1.2 章に書いてあったことですが、JavaScript でオブジェクト指向を実装するのにプロトタイプを利用できるそうです。だからプロトタイプを使用したコーディングが主流になっているということなのでしょうか?

プロトタイプを使用したコード例として、本に書いてあったように、Person クラスを以下のように定義したとします。

// Person クラスの疑似コンストラクター
var Person = function (name, lastname, birthdate) {
    this.initialize(name, lastname, birthdate);
}

// メンバー
Person.prototype.initialize = 
                 function (name, lastname, birthdate) {
    this.Name = name;
    this.LastName = lastname;
    this.BirthDate = birthdate;
}
        
// メンバー
Person.prototype.getAge = function () {
    return 18;
}

Person クラスの Own プロパティは Name, LastName, BirthDate のみです。しかしながら、以下のコードのように for...in で Person クラスの各要素をコンソールに出力すると、Name, LastName, BirthDate の他に、プロトタイプチェーンをたどって initialize, getAge も出力されてしまいます。上の画像の赤枠で示した部分が下記のコードの実行結果です。

var p = new Person("web", "surfer", "2017/6/30");

for (var key in p) {
    console.log(key + ':' + p[key]);
}

それを、以下のように、p.hasOwnProperty(key) が true になる要素のみをコンソールに出力すれば、上の画像の青枠部分に示した通り、Name, LastName, BirthDate のみとなります。

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + ':' + p[key]);
    }
}

上記は、あくまで自分が思いついた自分的に納得できる例で、他にもっと適切で分かりやすい例があるかもしれませんが・・・

Tags: ,

JavaScript

w2ui Grid

by WebSurfer 2015年12月26日 16:17

w2ui が提供している JavaScript ライブラリに Grid という表を表示するための widget があります。訳あって ASP.NET Web Forms アプリでちょっと使ってみましたので、使い方を忘れないように書いておきます。

w2ui Grid

(注:先の記事 GridView のヘッダ、列を固定(その 2)でも Grid という名前の同様な JavaScript ライブラリを紹介していますが、それとは別物です)

今回使った w2ui ライブラリはこの記事を書いている時点での最新版 1.4.3 です。jQuery も必須でとりあえず今回は自分が持っていたバージョン 1.8.3 を使いました。

たぶん、SQL Server などのデータベースからデータを取得して Grid で表示する際、どうやって Grid にデータを渡すかというところが一番の課題になると思いますので、そこのところを書いておきます。(他は w2ui の記事を読めば分かると思いますので割愛。手抜きでスミマセン)

簡単に書くと、Grid Overview のページの Example 2 に書いてあるように url にリソースを指定しておくと、Grid が url に指定されたリソースを非同期要求するので、要求を受けたら Example 2 に書いてある形式の JSON 文字列を応答として返すようにしておけば、後は表示まで全部 Grid が面倒見てくれます。

url に指定するリソースは、同じドメインにあって(AJAX なのでドメインが異なるのは NG)指定された形式の JSON 文字列を返すことができれば、.aspx ページ、HTTP ハンドラ、Web サービス、WPF、MVC のアクションメソッド、Web API などを使用できます。

ただし、Grid が非同期要求する際、{ "cmd":"get-records", ...} というデータが application/x-www-form-urlencoded 形式に変換され(JSON 文字列でないことに注意)、フォームデータとして POST されてきますので、そのフォームデータを使ってサーバー側で何か処置を行う場合は JSON 文字列を受けることが前提の Web サービス、WPF は使い勝手が悪そうです。

ASP.NET Web Forms アプリなら .aspx ページまたは HTTP ハンドラを使うのが都合がよさそうです。なので、今回は HTTP ハンドラを使用する例を書きました。

HTTP ハンドラ

Microsoft が提供している SQL Server サンプルデータベース Northwind の Orders テーブル(14 フィールド x 830 レコード)から全レコードを取得し、指定された形式の JSON 文字列にシリアル化して応答として返します。

シリアル化の方法は MSDN ライブラリの方法 : JSON データをシリアル化および逆シリアル化するを参考にしました。

コード内のコメントにも書きましたが、DateTime 型は \/Date(836406000000+0900)\/ のようにシリアル化されます。(詳しくは MSDN ライブラリの記事「スタンドアロン JSON のシリアル化」の「高度な情報 / DateTime ワイヤ形式」のセクションの説明を見てください)

クライアント側で形式変換できなければ、サーバー側で適当な文字列に変換する必要があります。(Grid を使った場合、形式変換するコードを割り込ませる場所がなさそうです。今回のサンプルではそのままにしています)

<%@ WebHandler Language="C#" 
    Class="_0139_w2uiOrdersHandler" %>

using System;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Runtime.Serialization;
using System.Web.Configuration;
using System.Collections.Generic;
using System.Runtime.Serialization.Json;

public class _0139_w2uiOrdersHandler : IHttpHandler 
{    
  public void ProcessRequest (HttpContext context) 
  {
    GridData data = new GridData();
    data.records = new List<Record>();
        
    string connString = WebConfigurationManager.
                        ConnectionStrings["Northwind"].
                        ConnectionString;
    string query = "SELECT [OrderID], [CustomerID]," +
        "[EmployeeID], [OrderDate], [RequiredDate]," +
        "[ShippedDate], [ShipVia], [Freight]," +
        "[ShipName], [ShipAddress], [ShipCity]," + 
        "[ShipRegion], [ShipPostalCode], [shipCountry]" + 
        "FROM [Orders]";

    using(SqlConnection conn = new SqlConnection(connString))
    {
      conn.Open();
      using (SqlCommand cmd = new SqlCommand(query, conn))
      {
        using (SqlDataReader reader = cmd.ExecuteReader())
        {
          if (reader != null)
          {
            while (reader.Read())
            {
              Record record = new Record();
                            
              record.OrderID = reader.GetInt32(0);
              record.CustomerID = reader.IsDBNull(1) ? 
                      null : reader.GetString(1);
              record.EmployeeID = reader.IsDBNull(2) ? 
                      null : (int?)reader.GetInt32(2);
              record.OrderDate = reader.IsDBNull(3) ? 
                      null : (DateTime?)reader.GetDateTime(3);
              record.RequiredDate = reader.IsDBNull(4) ? 
                      null : (DateTime?)reader.GetDateTime(4);
              record.ShippedDate = reader.IsDBNull(5) ? 
                      null : (DateTime?)reader.GetDateTime(5);
              record.ShipVia = reader.IsDBNull(6) ? 
                      null : (int?)reader.GetInt32(6);
              record.Freight = reader.IsDBNull(7) ? 
                      null : (decimal?)reader.GetDecimal(7);
              record.ShipName = reader.IsDBNull(8) ? 
                      null : reader.GetString(8);
              record.ShipAddress = reader.IsDBNull(9) ? 
                      null : reader.GetString(9);
              record.ShipCity = reader.IsDBNull(10) ? 
                      null : reader.GetString(10);
              record.ShipRegion = reader.IsDBNull(11) ? 
                      null : reader.GetString(11);
              record.ShipPostalCode = reader.IsDBNull(12) ? 
                      null : reader.GetString(12);
              record.ShipCountry = reader.IsDBNull(13) ? 
                      null : reader.GetString(13);
                            
              data.records.Add(record);
            }
          }
        }
      }
    }

    HttpResponse response = context.Response;
        
    // キャッシュは無効にする
    response.Cache.SetCacheability(HttpCacheability.NoCache);
    response.Cache.SetExpires(DateTime.Now.ToUniversalTime());
    response.Cache.SetMaxAge(new TimeSpan(0, 0, 0, 0));

    response.ContentType = "application/json; charset=utf-8";
        
    data.status = "success";
    data.total = data.records.Count;

    // JSON 文字列にシリアル化
    DataContractJsonSerializer ser = 
        new DataContractJsonSerializer(typeof(GridData));
    ser.WriteObject(response.OutputStream, data);

    // DateTime 型は \/Date(836406000000+0900)\/ のように
    // シリアル化される。
  }

  public bool IsReusable 
  {
    get 
    {
      return false;
    }
  }

}

[DataContract]
internal class GridData
{
    [DataMember]
    internal string status { get; set; }

    [DataMember]
    internal int total { get; set; }

    [DataMember]
    internal List<Record> records { get; set; } 
}

[DataContract]
internal class Record
{
    [DataMember]
    internal int OrderID { get; set; }
    
    [DataMember]
    internal string CustomerID { get; set; }
    
    [DataMember]
    internal int? EmployeeID { get; set; }
    
    [DataMember]
    internal DateTime? OrderDate { get; set; }
    
    [DataMember]
    internal DateTime? RequiredDate { get; set; }
    
    [DataMember]
    internal DateTime? ShippedDate { get; set; }
    
    [DataMember]
    internal int? ShipVia { get; set; }
    
    [DataMember]
    internal decimal? Freight { get; set; }
    
    [DataMember]
    internal string ShipName { get; set; }
    
    [DataMember]
    internal string ShipAddress { get; set; }
    
    [DataMember]
    internal string ShipCity { get; set; }
    
    [DataMember]
    internal string ShipRegion { get; set; }
    
    [DataMember]
    internal string ShipPostalCode { get; set; }
    
    [DataMember]
    internal string ShipCountry { get; set; }    
}

Grid を表示する .aspx ページ

上の HTTP ハンドラを以下のように url に設定すれば(以下のコードで 0139-w2uiOrdersHandler.ashx が上記の HTTP ハンドラ)、自動的に HTTP ハンドラに非同期呼び出しがかかって JSON 文字列が取得され、Grid にデータが表示されます。その結果が上の画像です。

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title></title>
  <script src="/jquery.js" type="text/javascript"></script>
  <script src="/w2ui.js" type="text/javascript"></script>
  <link href="/w2ui.css" rel="stylesheet" type="text/css" />
  <script type="text/javascript">
  //<![CDATA[
  $(function () {
    $('#myGrid').w2grid({
      name: 'myGrid',
      url: '0139-w2uiOrdersHandler.ashx',
      columns: [
       {field:'OrderID',caption:'Order ID',size:'7%'},
       {field:'CustomerID',caption:'Customer ID',size:'7%'},
       {field:'EmployeeID',caption:'Employee ID',size:'7%'},
       {field:'OrderDate',caption:'Order Date',size:'7%'},
       {field:'RequiredDate',caption:'Required Date',size:'7%'},
       {field:'ShippedDate',caption:'Shipped Date',size:'7%'},
       {field:'ShipVia',caption:'Ship Via',size:'7%'},
       {field:'Freight',caption:'Freight',size:'7%'},
       {field:'ShipName',caption:'Ship Name',size:'7%'},
       {field:'ShipAddress',caption:'Address',size:'7%'},
       {field:'ShipCity',caption:'City',size:'7%'},
       {field:'ShipRegion',caption:'Region',size:'7%'},
       {field:'ShipPostalCode',caption:'Postal Code',size:'7%'},
       {field:'ShipCountry',caption:'Country',size:'7%'}
      ]
    });
  });
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <div id="myGrid" style="height: 400px"></div>
  </form>
</body>
</html>

上のサンプル(14 フィールド x 830 レコード)でスクロールすると、Chrome 最新版ならそれなりに動きますが、IE9 あたりだと使い物にならないレベルの遅さでした。古いブラウザでの使用は考えてないのかもしれませんね。

Tags:

JavaScript

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  2017年10月  >>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar