WebSurfer's Home

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

正規表現パターンにコメント

by WebSurfer 2015年7月4日 17:33

.NET Framework の C# のコードで、正規表現のパターンにコメントをつける方法を備忘録として書いておきます。

正規表現のパターンにコメント付与

上の画像を見れば一目瞭然で、それ以上の説明は不要かもしれませんが、それではブログの記事としてはちょっと寂しいので追加情報なども以下に書いておきます。

正規表現については、自分的には MSDN の記事 ASP.NET の正規表現 が一番分かりやすく、いつも参考にさせてもらっています。

おかげさまで、自分でもある程度パターンを作れるようにはなったのですが、自分で作っておきながら後になって読むと意味不明ということがあります。

そういう時のために、正規表現パターンにコメントをつけておくと良いという MDSN の記事を見つけて真似しています。

その記事見つからなくなってしまったので、以前自分が書いたコードを探して、それを参考にしてコメントをつけていましたが、探して見つけるのが結構大変ということで、ブログに書いておくことにしました。

以下は完全に余談ですが・・・

例として、パスワードの文字列で、条件として「半角大文字アルファベットと半角数字のみの 4 文字以上、8 文字以下で構成され、それぞれ最低 1 文字を含む」というケースを考えてみます。

そのようなケースでは、上に紹介した「ASP.NET の正規表現」のページの「高度なトピック」のセクションに書いてある "ルックアラウンド処理" を利用するのが便利だと思います。

「正の先読み」および「負の先読み」の両方のケースで書いてみました。前者が下のコードの regex1、後者が regex2 です。

Regex regex1 = new Regex(@"
    ^               # 開始のアンカー
    (?=.*\d)        # 数字が最低 1 文字あること
    (?=.*[A-Z])     # 英大文字が最低 1 文字あること
    [A-Z0-9]{4,8}   # 英大文字または数字が 4 ~ 8 文字
    $               # 終了のアンカー",
    RegexOptions.IgnorePatternWhitespace);

Regex regex2 = new Regex(@"
    (?!^[0-9]*$)    # 全部が数字ということはない
    (?!^[A-Z]*$)    # 全部が英大文字ということはない
    ^               # 開始のアンカー
    ([A-Z0-9]{4,8}) # 英大文字または数字が 4 ~ 8 文字
    $               # 終了のアンカー",
   RegexOptions.IgnorePatternWhitespace);

string[] testStrings = { "AB1", "AB12", "ABCDEF", "123456", 
                         "ABCDEFG1", "1234567A", "ABCD12345", 
                         "ABC123dE", "ABCあ123", "ABC%1234" };

foreach (string s in testStrings)
{
    Console.WriteLine(s + " => " + regex1.IsMatch(s) + " (1)");
    Console.WriteLine(s + " => " + regex2.IsMatch(s) + " (2)");
}

// 結果は:
// AB1 => False (1)
// AB1 => False (2)
// AB12 => True (1)
// AB12 => True (2)
// ABCDEF => False (1)
// ABCDEF => False (2)
// 123456 => False (1)
// 123456 => False (2)
// ABCDEFG1 => True (1)
// ABCDEFG1 => True (2)
// 1234567A => True (1)
// 1234567A => True (2)
// ABCD12345 => False (1)
// ABCD12345 => False (2)
// ABC123dE => False (1)
// ABC123dE => False (2)
// ABCあ123 => False (1)
// ABCあ123 => False (2)
// ABC%1234 => False (1)
// ABC%1234 => False (2)

「正の先読み」というのが (?=<pattern>) という形のもので、対象文字列を先読みしていって <pattern> の条件に合えば true になります。例えば、上のコードでいうと regex1 の (?=.*\d) が該当します。<pattern> は .*\d で、「任意の文字 0 回以上の繰り返しのあと数字がある」という条件になります。

「負の先読み」というのは (?!<pattern>) という形のもので、「正の先読み」の逆すなわち否定になり、<pattern> の条件に合わないものが true になります。上のコードの regex2 の (?!^[0-9]*$) の場合、<pattern> は ^[0-9]*$ で、「文字列の最初から最後まで全ての文字が数字ではない」という条件になります。

後者の方はホントにこれでいいのか自信がないですが(汗)、上のコードの中のコメントに書いたマッチするか否かの結果を見る限りでは、よさそうな感じです。(笑)

Tags:

.NET Framework

識別子名に日本語

by WebSurfer 2015年3月17日 17:23

変数、メソッド、プロパティなどの識別子名に、見易さや保守性を考えて日本語を使うという話を時々聞きますが、言語仕様上許されているからと言って安易に使うと思わぬ副作用がありそうという話を書きます。

自分が気がついた例に限っての話ですが、それは ASP.NET MVC のモデルのプロパティ名、コントローラーのアクションメソッドの引数名です。

モデルのプロパティ名は html ソースでは name 属性に設定され、クライアント側でのユーザー入力の検証やサーバー側でのモデルバインディングに使われます。

具体的には次の通りです。

先の記事 コレクションのデータアノテーション検証 で紹介したモデル / ビュー / コントローラーのコードを見てください。そのモデルには CountryList と Name というプロパティ名が使われています。それを元に以下のようなビューを書くと、

@Html.LabelFor(m => m.CountryList[i].Name)
@Html.EditorFor(m => m.CountryList[i].Name)
@Html.ValidationMessageFor(m => m.CountryList[i].Name)

生成される html ソースは以下のようになります。

<label for="CountryList_0__Name">国名</label>
<input class="text-box single-line" 
  data-val="true" 
  data-val-length="国名 は 15 文字以内" 
  data-val-length-max="15"
  data-val-required="国名 は必須" 
  id="CountryList_0__Name"
  name="CountryList[0].Name" 
  type="text"
  value="Italy" />
<span class="field-validation-valid" 
  data-valmsg-for="CountryList[0].Name" 
  data-valmsg-replace="true">
</span>

上記の CountryList と Name が日本語になった場合、jQuery ライブラリを使ったクライアント側での検証がうまく動くのか、ブラウザで form が submit されると き name 属性がどうなるか、サーバー側できちんとモデルバインディングされるかが気がかりです。

モデルのプロパティ以外で思いつくものとしてはアクションメソッドの引数名があります。これもサーバー側でのモデルバインディングに関係します。

他にも予期できない副作用があるかもしれません。十二分に検証すれば済むかもしれませんが、そもそも余計な気苦労と不要な手間です。そこまでして日本語を使う理由はなさそうです。

クライアント側に影響がありそうな ASP.NET MVC アプリの識別子名で、日本語を使っても問題なさそうなのはコントローラーのアクションメソッド名ぐらいでしょう���?

例えば、以下のようにアクションメソッド名は日本語でも、ActionNameAttribute で英語名 Countries を付与すればブラウザからは Countries で呼べます。

[ActionName("Countries")]
public ActionResult 国リスト取得()
{
  return View();
}

でも、やっぱり日本語を使うのは個人的にはお勧めではないです。例えば、Countries でなら呼べますが Countries では 404 エラーです。違いが分かりますか?

答は、名前の最後の s が半角 / 全角の違いということです。

そんなエラーはすぐ気がつくと思われるかもしれませんが、たとえ 1 分で気がついたとしても時間と労力の無駄には変わりないということで、やはり日本語は使用しない方がよいと自分は思います。

Tags: ,

.NET Framework

Web サービス経由で非接続型データアクセス

by WebSurfer 2014年8月23日 16:50
2018/3/4 追記:
Microsoft によると Web サービスは "Legacy Technology" なので WCF を使えとのことゆえ、接続先を WCF サービスに変更し、非同期にアクセスするサンプルを作ってみました。興味がありましたら記事「WCF サービス経由で非接続型データアクセス」を見てください。

DataGridView と型付 DataSet + TableAdapter を用いて非接続型データアクセスを行う Windows アプリケーションで、Web サービス経由で SQL Server のデータの取得更新を行う例の紹介です。(Windows アプリから直接 SQL Server に接続するのではなく)

DataGridView

Visual Studio のデータソース構成ウィザードを使うと、MSDN ライブラリの Windows フォーム アプリケーションでのデータへの接続 の図のような構成の Windows アプリケーションを作成できます。具体的な作成手順例は、チュートリアル「10 行でズバリ !! 非接続型のデータ アクセス」を見てください。

上に紹介したチュートリアルの例では Windows アプリから直接 SQL Server に接続していますが、セキュリティ上の問題などで、Windows アプリ ⇔ サーバー ⇔ SQL Server というようにサーバーを介してアクセスしたいということがあると思います。

Web サーバー (IIS) を利用し、それに Web サービス(.asmx)を実装して、Windows アプリケーションとの間で型付 DataSet をやりとりすることで Windows アプリ ⇔ サーバー ⇔ SQL Server という構成を実現できます。

(1) Web サービス

まず Web サービスですが、(a) SQL Server から型付 DataSet にデータを取得して Windows アプリケーション渡すメソッド、(b) ユーザーが編集済みの型付 DataSet を受け取って SQL Server のレコードを更新するメソッドを実装します。

具体例は以下のようになります。GetDataSet メソッドが上記 (a)、Update メソッドが上記 (b) に該当します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;

namespace WebApplication1
{
  using ProductsDataSetTableAdapters;
    
  [WebService(Namespace = "http://tempuri.org/")]
  [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  [System.ComponentModel.ToolboxItem(false)]
  public class ProductsWebService : WebService
  {
    [WebMethod]
    public ProductsDataSet GetDataSet()
    {
      ProductsDataSet dataset = new ProductsDataSet();
      ProductsTableAdapter adapter = 
                          new ProductsTableAdapter();            
      adapter.Fill(dataset.Products);
      return dataset;
    }

    [WebMethod]
    public int Update(ProductsDataSet dataset)
    {
      TableAdapterManager manager = new TableAdapterManager();
      manager.ProductsTableAdapter = new ProductsTableAdapter();
      return manager.UpdateAll(dataset);
    }
  }
}

SQL Server データベースには、Microsoft が無償で提供しているサンプルデータベース Northwind の Products テーブルを使っています。

ProductsDataSet, ProductsTableAdapter, TableAdapterManager は、 Visual Studio のデータソース構成ウィザードを使って自動生成させた .xsd ファイル下の .Designer.cs に含まれる型付 DataSet + TableAdapter + TableAdapterManager です。

(2) クライアント・アプリケーション

上記の Web サービスをクライアント・アプリケーションでは以下のように利用できます。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace UpdateUsingWebService
{
  public partial class Form2 : Form
  {
    private ProductsServiceReference.
                        ProductsWebServiceSoapClient client;
    private ProductsServiceReference.
                        ProductsDataSet productsDataSet;

    public Form2()
    {
      InitializeComponent();
      InitializeComponent2();
      this.client = new ProductsServiceReference.
                            ProductsWebServiceSoapClient();
    }

    private void productsBindingNavigatorSaveItem_Click(
        object sender, EventArgs e)
    {
      this.Validate();
      this.productsBindingSource.EndEdit();
            
      // Web サービスに渡すのはユーザーが編集した行のみで可
      ProductsServiceReference.ProductsDataSet ds =
                  (ProductsServiceReference.ProductsDataSet)
                           this.productsDataSet.GetChanges();

      // 編集済みの型付 DataSet を Web サービスに渡し、更新
      // をかける。戻り値 n は更新されたレコード数
      int n = this.client.Update(ds);

      // 更新後の型付 DataSet を取得。DataGridView 書き換え
      this.productsDataSet = this.client.GetDataSet();
      this.productsBindingSource.DataSource = 
                                    this.productsDataSet;
    }

    private void Form2_Load(object sender, EventArgs e)
    {
      // Web サービスより型付 DataSet を取得
      this.productsDataSet = this.client.GetDataSet();
      this.productsBindingSource.DataSource = 
                                     this.productsDataSet;
    }

    // ・・・中略・・・

    private void InitializeComponent2()
    {
      // ・・・中略・・・
    }

  }
}

まず、Visual Studio のサービス参照の追加ウィザードを利用して、上記 (1) で作成した Web サービスを参照し、プロキシクラスと型付 DataSet(上記のコード例では ProductsWebServiceSoapClient と ProductsDataSet)を自動生成させます。

次に、Visual Studio のデータソース構成ウィザードを使って、上記 (1) で作成した型付 DataSet + TableAdapter + TableAdapterManager と全く同じものを自動生成させます。

その上で、Visual Studio のデザイン画面で、「データソース」ウィンドウの項目を Form 画面にドラッグ&ドロップすると、DataGridView, BindingSource, BindingNavigatorなどのコードが自動生成されます。

それらを組み合わせれば容易に実装できるはずです。

Tags: , ,

.NET Framework

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar