yamicha.com's Blog - Presented by yamicha.com
Blog yamicha.com's Blog - 2017/11 の記事
[1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30]

yamicha.com's Blog
 諸事情により、現在更新休止中。ご了承ください。もし今後ブログを再開することがあるとすれば、その際にはこのブログスクリプトではなく、新しく開発したものによるかもしれません。
 当ブログ管理者についてはこちらをご参照。
開発魔法(737)
社会問題(733)
お知らせ(11)
質問・バトン回答(15)
ゲスト出演(8)
経済・知的財産(150)
ゲーム開発(182)
[Ada] 勝手に補足
- Note
- 金配りの次の一手


- Endless Ultimate Diary
- 銃世界

漢字バトン
- うるる雑記帳
- 漢字接力棒

ツキアイゲノムバトン
- ブログ@うにうに画像倉庫
- あぶ内閣

縺イ縺セ縺、縺カ縺励ヰ繝医Φ
- 月夜のボヤキ
- 騎士サーラバトン
パスワードを使う
名無し (2012/02/27)


開発者解放裁判
yamicha.com (2010/03/14)
Winnyに関しては、私も「純白」とまでは考えておりませんし、使用し..

開発者解放裁判
通りすがり (2010/03/08)
winnyに関しては「ダウンロードソフト板」なんてところを拠点に開発..

新型インフルエンザの恐怖
いげ太 (2009/11/03)
> C#などの「int Some(int , int)」は、F#では「(int * int) ->..

時効に関する思考
yamicha.com (2009/08/31)
>いげ太さんコメントありがとうございます。手元にドキュメントが少..
Homepage
Blog Top
Normal View
List View
Search
Calendar
Comment List
Trackback List
Blog RSS
Send Trackback
Phone Mode
Administrator
yamicha.com
Blog
るううるる。
Source
法令データ提供システム
FindLaw
Development
Java2 Platform SE 6
Java EE 6 API
MySQL Developer Zone
PHP Reference
MSDN Library
Ada Reference Manual
Objective Caml
Python Documentation
Erlang
Prolog Documents
 垂オ訳ございませんが、現在このブログではトラックバックを受け入れていません。

 この記事に対してリンクされる場合には、こちらのURLをご利用ください。
http://void.yamicha.com/blog/blog.cgi?mode=view&number=769
 上記URLをトリプルクリックされますと、簡単にURL全体の選択が行えます。

※以下の記事がトラックバックされます。
逆を以って累を助く
2010/06/27(Sun)23:15:08
 二大政党がそれぞれ消費税を競うという異例の2010年参院選ですが、やはり消費税は選挙の嫌われ者であるのか、民主党の支持には早速かげりが見え始めました。菅氏が「消費税10%」を実質的な公約とした部分が大きいようです。世論調査でも消費税の是非は真っ二つに割れており、消費税増税に理解を示す人も多数に上る反面、反対意見が根強いこともうかがわせます。
 確かに、消費税の増税は国民にとって望ましいことではありませんが、実際の国民はそれほど愚かではありません。麻生政権の金配り政策が失敗し、鳩山政権で「子ども手当て」があまり評価されなかったのを見ての通り、国民は目先の利益にばかり飛びつくわけではなく、おそらく国民の大多数は消費税を含む負担増がどうしても避けられないことを認識しています。
 消費税を上げるとなれば、それとセットで無駄の削減も絶対に必要ですが、民主党政権も事業仕分けである程度無駄をなくすのには成功したものの、これ以上に巨額の財源を歳出削減によって確保するあてはありません。今後とも歳出削減の努力を平行して行うのは当然としても、歳入を増やす方法を検討しないわけにはいきません。一部の弱小政党は、消費税増税論をあたかも「歳出削減を行わない」ような意味と解釈して批判したりしていますが、これは詭弁の一種に過ぎません。そして実際、おそらく大多数の国民は、必死で歳出削減の努力を続けたとしても、消費税増税の必要性がなくなるわけではないことを認識しているはずです。
 したがって、国民の消費税増税への理解はいつになく深まっているといえるでしょう。議論しようとするだけで大騒ぎになっていた今までと違い、議論の環境は十分に整っているといえます。ただ、それでも増税を口にした民主党の支持率が下落してしまうのは、鳩山時代の衆院の公約に反することもありますが、何より法人税減税とセットにしてしまった点が非常に大きいのではないかと推測されます。
 消費税は非常に逆進性が強い税ですから、これを累進的な政策の財源として使わないのであれば、それは不公平この上ない税制となります。つまり、消費税を財源として法人税を下げる行為は道理に反しているのです。これでは消費税増税に反対する人が増えるのも当たり前です。
 なお、自民党は消費税を福祉目的で使用するとの主張を展開していますが、もし法人税を減税し、さらに減税分の財源を逆進的でない方法で捻出しないのであれば、ただの言葉遊びに過ぎません。「消費税を増税して法人税を下げ、福祉は国債でまかなう」行為と「消費税を増税して福祉に充当、法人税減税は国債でまかなう」行為の間には、本質的に何の違いもないためです。むしろ、自民党はかねてから経済団体の主張をなぞったような主張をしているのですから、素直に「消費税増税と法人税減税をセットにする」と明確に方針を示した方が分かりやすくなります。
 法人税減税の財源としては、消費税などを増税して充当するのではなく、法人税の複雑な控除を廃止して財源を確保するとの主張も存在するようです。この場合は法人税の課税方法が変化するだけで、別の財源は必要ありません。しかし、仮にその方法を用いるのであれば、それを主張する政党はそのやり方と試算をしっかり訴える必要があります。八方美人的な言い方をしておきながら、例によって後から計算通りにならないと判明し、消費税増税分の財源に手をつけるような事態にでもなれば、詐欺以外の何者でもありません。
 また、自民党が攻勢に出る一方で、民主党が消費税発言でことさら支持を失った理由としては、民主党が一部経済団体の主張をなぞるような政策を言い始めたこともあるはずです。「消費税を増税して法人税を下げる」政策は繰り返し経団連が要求してきたものですし、その上に偽装請負が問題になった際には「それを合法化すべきだ」と主張してみたり、「みなし役員」問題を見れば結末は明らかでありながら年収400万円を基準とする無賃残業合法化を主張してみたりと、最近の同組織の傍若無人ぶりには目を覆いたくなるものがありました。さらには「団体献金」問題からも明らかですが、このような団体が裏で絡んでいると、制度改革や国民本位の政治は容易ではなくなります。自民党が先の衆院選で敗北したのも、経団連への退場勧告の意味が多分に含まれていたはずです。そのせいで経団連の影響力は地に落ち、会長にはこれまでの不文律を破って米倉氏が立てられました。
 ところが、今度は民主党が似たようなことを主張し始めたとなれば、とても冗談では済まされません。経済団体と蜜月の自民党ではもう改革は無理と踏んで民主党に取り替えたら、その民主党もまた同じことを言い出したというのが現在の状況なのです。自民党に比べて民主党の消費税発言が支持されないのは、その期待を裏切ったことによる部分があると考えるべきでしょう。
 なお、民主党は所得税の最高税率の引き上げにも言及しているようです。こちらは累進課税ですので、消費税に固有のいくつかの問題は回避または軽減できますが、もし所得税最高税率に言及だけはしておきながら、実際には消費税だけ上げて所得税には手をつけないようなことがあれば、実行する気もない累進課税をダシにして逆進増税を実現させたと批判されても仕方がありません。実現する気があるなら変更点や目安の時期をしっかり明示し、する気がないなら「しない」とはっきり断言しなくてはなりません。

 JPA 2.0の何とも地味な変更点として、Nested Embeddableが存在します。意味はそのまま、@Embeddableをネストできるというだけです。これはこれで便利な局面もありそうですが、機能として面白いかどうかは微妙なところです。
 @AttributeOverride(s)との合わせ技でそれなりに色々な使い方も可能ですが、今回は単純に「読み仮名を登録するとソート用データを自動的に生成してくれるクラス」を「記事タイトル」内に持たせ、さらに「記事項目」にそのタイトルデータを持たせる簡易な辞書を実装しています。
/com
 /yamicha
  /dic
   @Embeddable Ruby.java
   @Embeddable Title.java
   @Entity Content.java
   @Stateless DictionalAccess.java
   @WebServlet DictionalServlet.java
/META-INF
 persistence.xml
 Ruby.javaやTitle.javaは@Embeddableですから、流用したり複数個のオブジェクトを使用するなど@Embeddableらしい使い方が可能です。そうでもしなければ@Embeddableの意味があまりありませんので、そのうち実際にそのように使用してみるとしましょう。
 persistence.xmlに変更はありません。
<?xml version="1.0" encoding="UTF-8"?>

<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="MySQL" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/MySQL</jta-data-source>
<properties>
<property name="eclipselink.jdbc.driver"
value="com.mysql.jdbc.Driver" />
<property name="eclipselink.ddl-generation" value="create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
<property name="eclipselink.target-database" value="MySQL" />
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</persistence-unit>
</persistence>
 Ruby.javaにはルビ整列用文字列生成機構を実装しています。
package com.yamicha.dic;

import javax.persistence.*;

@Embeddable public class Ruby
  implements java.io.Serializable{
  // ※マップ中の '\0' はダミーデータ
  private static final char RUBY_MAP[][] = {
    {'ぁ' , 'あ'} ,
    {'ぃ' , 'い'} ,
    {'ぅ' , 'う' , '\0' , 'ヴ'} ,
    {'ぇ' , 'え'} ,
    {'ぉ' , 'お'} ,

    {'\0' , 'か' , '\0' , 'が'} ,
    {'\0' , 'き' , '\0' , 'ぎ'} ,
    {'\0' , 'く' , '\0' , 'ぐ'} ,
    {'\0' , 'け' , '\0' , 'げ'} ,
    {'\0' , 'こ' , '\0' , 'ご'} ,

    {'\0' , 'さ' , '\0' , 'ざ'} ,
    {'\0' , 'し' , '\0' , 'じ'} ,
    {'\0' , 'す' , '\0' , 'ず'} ,
    {'\0' , 'せ' , '\0' , 'ぜ'} ,
    {'\0' , 'そ' , '\0' , 'ぞ'} ,

    {'\0' , 'た' , '\0' , 'だ'} ,
    {'\0' , 'ち' , '\0' , 'ぢ'} ,
    {'っ' , 'つ' , '\0' , 'づ'} ,
    {'\0' , 'て' , '\0' , 'で'} ,
    {'\0' , 'と' , '\0' , 'ど'} ,

    {'\0' , 'な'} ,
    {'\0' , 'に'} ,
    {'\0' , 'ぬ'} ,
    {'\0' , 'ね'} ,
    {'\0' , 'の'} ,

    {'\0' , 'は' , '\0' , 'ば' , 'ぱ'} ,
    {'\0' , 'ひ' , '\0' , 'び' , 'ぴ'} ,
    {'\0' , 'ふ' , '\0' , 'ぶ' , 'ぷ'} ,
    {'\0' , 'へ' , '\0' , 'べ' , 'ぺ'} ,
    {'\0' , 'ほ' , '\0' , 'ぼ' , 'ぽ'} ,

    {'\0' , 'ま'} ,
    {'\0' , 'み'} ,
    {'\0' , 'む'} ,
    {'\0' , 'め'} ,
    {'\0' , 'も'} ,

    {'ゃ' , 'や'} ,
    {} ,
    {'ゅ' , 'ゆ'} ,
    {} ,
    {'ょ' , 'よ'} ,

    {'\0' , 'ら'} ,
    {'\0' , 'り'} ,
    {'\0' , 'る'} ,
    {'\0' , 'れ'} ,
    {'\0' , 'ろ'} ,

    {'\0' , 'わ'} ,
    {} ,
    {} ,
    {} ,
    {'\0' , 'を'} ,

    {'\0' , 'ん'}
  };

  private String ruby;
  private String sort;

  public Ruby(){
  }
  public Ruby(String r){
    setRuby(r);
  }

  public String getRuby(){
    return ruby;
  }
  public String getSort(){
    return sort;
  }

  private static final char FIRST = ' ';  // 0x20
  public void setRuby(String r){
    ruby = r;

    StringBuffer sb = new StringBuffer();
    StringBuffer sbt = new StringBuffer();

    int before = -1;
    char bc = '';
    for(int i = 0; i < r.length(); i++){
      char c = r.charAt(i);

      int value = 0;
      int type = 0;

      if(c != 'ー'){
        boolean match = false;
        for(int v = 0; v < RUBY_MAP.length; v++){
          for(int t = 0; t < RUBY_MAP[v].length; t++){
            if(RUBY_MAP[v][t] == c){
              match = true;

              value = v;
              type = t;

              before = v;
              bc = c;
            }
          }
          if(match)
            break;
        }

        if(!match)
          throw new IllegalArgumentException(
            "文字 " + c + " は使用できません。");
      }else{
        // 前の文字から母音を取り出す
        if(before == -1)
          throw new IllegalArgumentException(
            "伸ばす音は先頭に配置できません。");

        // 「ん」の場合は「ん」が続くとみなす
        // それ以外は母音となる
        // 伸ばす音が2つ以上連続している場合は
        // 同じ音が続いているとみなされる
        if(bc == 'ん'){
          value = before;
          type = 1;  // 優先度は通常の「ん」より低い
        }else{
          value = before % 5;
          type = 2;  // 優先度は2(「ぅ」「う」より後で「ヴ」より前)
        }
      }

      sb.append((char)(FIRST + value + 1));
      sbt.append((char)(FIRST + type + 1));
    }

    sb.append(FIRST);

    sb.append(sbt.toString());

    setSort(sb.toString());
  }
  private void setSort(String s){
    sort = s;
  }
}
 ソート順は基本的に辞書順です。すなわち、五十音(小文字や濁音を区別せず、伸ばす音は発音に変換したもの)をまず比較し、五十音では差がない場合は小文字、清音、伸ばし音、濁音、半濁音の順に並べます。「ヴ」に関しては、「う」の濁点と扱っている辞書と、「ば」行で扱っている辞書がありますが、ここでは前者の方式を採用しました(後者の方式を用いるなら、最初から「ば」行で読みを登録すれば済むので、そもそも「ヴ」をルビ用文字に加える必要がない)。
 ちなみに、日本語の五十音は「や」行を「やいゆえよ」、「わ」行を「わいうえを」と扱い、さらに「ん」を入れたとしても51個に過ぎず、文字の種別(清音の他、濁音、半濁音、伸ばす音、小文字)は5パターン程度に過ぎないため、当初は五十音に6ビット(64通り)、種別に3ビット(8通り)の1文字9ビットを使用し、五十音データと種別データの区切りとして1ビットを使用する(したがって、ソート用文字列のサイズは「文字数 * 9 + 1ビット」)実装としていましたが、何とEclipseLinkのJPQLは(あるいはJPAのJPQL仕様は)byte[]をORDER BYできないらしいため、仕方なくAscii文字を使用する形式に書き直した経緯があります。おかげで五十音に1バイト、種別に1バイト、さらに五十音と種別の区切りに1バイトで、サイズは「文字数 * 2 + 1バイト」です。なお、VARBINARYはMySQL側では正しくORDER BYできるため、なおさらJPAで動かないのが理不尽です。
 これに比べ、Title.javaやContent.javaはごく単純な@Embeddableや@Entityです。
// Title.java
package com.yamicha.dic;

import javax.persistence.*;

@Embeddable public class Title
	implements java.io.Serializable{
	private String title;
	private Ruby ruby;

	public Title(){
		ruby = new Ruby();
	}
	public Title(String t , String r){
		this();
		title = t;
		ruby.setRuby(r);
	}
	public Title(String t , Ruby r){
		this();
		title = t;
		ruby = r;
	}

	public String getTitle(){
		return title;
	}
	@Embedded public Ruby getRuby(){
		return ruby;
	}

	public void setTitle(String t){
		title = t;
	}
	public void setRuby(Ruby r){
		ruby = r;
	}
}

// Content.java
package com.yamicha.dic;

import javax.persistence.*;

@Entity @Table(name="dic_content" , schema="yamicha")
	public class Content implements java.io.Serializable{
	private int id;
	private Title title;
	private String description;

	public Content(){
		title = new Title();
	}
	public Content(Title t , String d){
		this();
		title = t;
		description = d;
	}

	@Id @GeneratedValue @Column(name="id") public int getId(){
		return id;
	}
	@Embedded public Title getTitle(){
		return title;
	}
	@Column(name="description" , columnDefinition="TEXT") @Lob
		public String getDescription(){
		return description;
	}

	public void setId(int i){
		id = i;
	}
	public void setTitle(Title t){
		title = t;
	}
	public void setDescription(String d){
		description = d;
	}
}
 DictionalAccess.javaでデータの取得や追加を行います。
package com.yamicha.dic;

import javax.ejb.*;
import javax.annotation.*;
import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;

@Remote @Stateless(name="DictionalAccess" , mappedName="ejb/DictionalAccess")
	public class DictionalAccess{
	@PersistenceContext(unitName="MySQL") private EntityManager em;

	public void add(String title , String ruby , String desc){
		if(title == null || title.isEmpty())
			throw new IllegalArgumentException(
				"タイトルがありません。");
		if(ruby == null || ruby.isEmpty())
			throw new IllegalArgumentException(
				"ふりがながありません。");
		if(desc == null || desc.isEmpty())
			throw new IllegalArgumentException(
				"本文がありません。");

		em.persist(new Content(new Title(title , ruby) , desc));
	}

	public List getContents(){
		return em.createQuery(
			"SELECT c FROM Content c ORDER BY c.title.ruby.sort" ,
			Content.class).getResultList();
	}
}
 特筆すべきは、せいぜいORDER BY程度です。なぜかbyte[]をソートしてくれないのは困ったものです。
 DictionalServlet.javaで登録フォームや表示を実装しています。
package com.yamicha.dic;

import javax.servlet.annotation.*;
import javax.ejb.*;
import javax.annotation.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.persistence.*;
import java.io.*;
import java.util.List;
import java.util.ArrayList;

@WebServlet(name="dictionalservlet" , urlPatterns={"/*"})
  public class DictionalServlet extends HttpServlet{
  @EJB(beanName="DictionalAccess") private DictionalAccess da;

  public void doPost(HttpServletRequest request ,
    HttpServletResponse response) throws IOException{
    doGet(request , response);
  }
  public void doGet(HttpServletRequest request ,
    HttpServletResponse response) throws IOException{
    //da.regist();

    request.setCharacterEncoding("UTF-8");
    response.setHeader("Content-type" , "text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();

    out.println("<html>");
    out.println("<head>");
    out.println("<title>Dictionaly</title>");
    out.println("</head>");
    out.println("<body>");

    out.println("<b>Dictionaly</b><br />");
    out.println("<a href=\"?c=form\">新しい項目の登録</a><hr />");

    String c = request.getParameter("c");

    if("add".equals(c)){
      try{
        da.add(request.getParameter("title") ,
          request.getParameter("ruby") ,
          request.getParameter("description"));

        c = null;
      }catch(EJBException e){
        out.println(e.getCausedByException().getMessage());
      }
    }

    if(c == null || c.isEmpty()){
      List<Content> contents = da.getContents();
      for(Content content : contents){
        Title title = content.getTitle();
        Ruby ruby = title.getRuby();

        out.println("<p>");
        out.println("<b>" + title.getTitle() + "</b><small>(" +
          ruby.getRuby() + ")</small><br />");
        out.println(content.getDescription().replace("\n" , "<br />"));
        out.println("</p>");
      }
    }else if("form".equals(c)){
      out.println("<form action=\"?\" method=\"POST\">");

      out.println("<table border=\"0\">");
      out.println("<tr>");
      out.println("<td>記事名</td>");
      out.println("<td><input type=\"text\" " +
        "name=\"title\" size=\"30\" /></td>");
      out.println("</tr>");

      out.println("<tr>");
      out.println("<td>ふりがな</td>");
      out.println("<td><input type=\"text\" " +
        "name=\"ruby\" size=\"30\" /><br />");
      out.println("<small>ひらがなと「ー」「ヴ」のみ有効</small></td>");
      out.println("</tr>");

      out.println("<tr>");
      out.println("<td>記事内容</td>");
      out.println("<td><textarea name=\"description\" " +
        "cols=\"50\" rows=\"6\"></textarea></td>");
      out.println("</tr>");
      out.println("</table>");

      out.println("<input type=\"hidden\" name=\"c\" value=\"add\" />");
      out.println("<input type=\"submit\" value=\"この内容を登録\" />");

      out.println("</form>");
    }

    out.println("</body>");
    out.println("</html>");

    out.close();
  }
}
 後は適当にデータを登録するだけです。
 データはこのように整列されて表示されます。Ruby.javaもTitle.javaも@Embeddableであるため、他にルビによるソートが必要な記事タイトルや人名など何らかのものがある場合、Title.javaを再利用できます。
 余談ながら、ソート用データは次のような文字列となっています。
SELECT TITLE , RUBY , SORT FROM dic_content ORDER BY SORT;

+--------+----------+-----------+
| TITLE  | RUBY     | SORT      |
+--------+----------+-----------+
| 州     | しゅう   | ,F# "!"   |
| シュー | しゅー   | ,F# "!#   |
| 私有   | しゆう   | ,F# """   |
| 十     | じゅう   | ,F# $!"   |
| 自由   | じゆう   | ,F# $""   |
| 修理   | しゅうり | ,F#J "!"" |
| 首都   | しゅと   | ,F4 "!"   |
+--------+----------+-----------+
カテゴリ [開発魔法][社会問題] [トラックバック 0][コメント 0]
<- 前の記事を参照 次の記事を参照 ->

- Blog by yamicha.com -