おでんはじめました。

required ちくわぶ and 巾着,optional はんぺん.

C#でリソースファイルからテキストを取得する

いつも忘れてしまうのでメモ。

VSでファイルを追加してプロパティのビルドアクションを「埋め込まれたリソース」にするのを忘れないこと。

//現在のコードを実行しているAssemblyを取得
System.Reflection.Assembly myAssembly = System.Reflection.Assembly.GetExecutingAssembly();

//ネームスペースがkj.sample、リソース名がtest.xmlの場合
System.IO.StreamReader sr = new System.IO.StreamReader(myAssembly.GetManifestResourceStream("kj.sample.test.xml"), Encoding.UTF8);
if (sr == null) throw new Exception("リソースを取得できない");
string s = sr.ReadToEnd();
sr.Close();

リソースの一覧の取得方法もメモ。

//指定されたマニフェストリソースを読み込む
string[] resnames=myAssembly.GetManifestResourceNames();
foreach (string res in resnames) {
  Console.WriteLine("resource {0}",res);
}

品詞分解してWordPressで検索するまで(その2、投稿編)

その1で作成したテキストを使ってWordPressへ一括で投稿するまでをやります。

XML-RPCの準備

WordPressへの投稿はXML-RPCを使う。 JSON REST APIはよくわからなかったので次の課題(汗。

XML-RPCを使うとWordPressの外側から投稿やカテゴリーの操作など一通りの作業ができる。 すべてのAPIは下記参照。

XML-RPC WordPress API « WordPress Codex

XML-RPCのライブラリはいくつかあるらしいけどincutioが使いやすそうだったのでこれを使う。

The Incutio XML-RPC Library for PHP

上記からIXR_Library.phpをダウンロードしてサイトの任意の場所へコピーする。

IXR_Library.phpの使い方

wp.newPostで投稿する場合。

<?php
/* inctioのライブラリ呼び出し */
include_once(‘IXR_Library.php');

/* 対象とするWordPressのサイト */
$client = new IXR_Client(“http://sample.co.jp/xmlrpc.php”);
$status = $client->query(
  "wp.newPost", //使うAPIを指定(wp.newPostは、新規投稿)
  1, // blog ID: 通常は1、マルチサイト時変更
  $wp_username, // ユーザー名
  $wp_password, // パスワード
  array(
    'post_author' => 2, // 投稿者ID 未設定の場合投稿者名なしになる。
    'post_status' => 'publish', // 投稿状態
    'post_title' => 'タイトル', // タイトル
    'post_content' => '投稿本文', // 本文
    'terms' => array('category' => array(1)) // カテゴリ追加
  )
);
if(!$status){
  die('Something went wrong - '.$client->getErrorCode().' : '.$client->getErrorMessage());
} else {
  $post_id = $client->getResponse(); //返り値は投稿ID
}

post.phpを作成する

投稿用のphp(post.php)を作成する。このphpC#から呼び出して使う。

作成したpost.phpWordPressのサイトの任意のフォルダにコピーする。

今回はWordPressのサイトの下のxmlrpcフォルダを作成してそこにコピーする。

  • フォルダ構成 www.sample.co.jp(WordPressのサイト)

 xmlrpc.php

 xmlrpcフォルダ

  IXR_Library.php

  post.php

  • 全部のソース(post.php
<?php
/**
品詞分解されたデータを投稿する
*/
include_once('IXR_Library.php');  //inctioのライブラリ呼び出し

//WordPressのサイトのルートにはxmlrpc.phpがある(初めから?)
$client = new IXR_Client("http://" . $_SERVER['SERVER_NAME'] . "/xmlrpc.php");

$user = $_POST['user']; //ユーザー名
$pass = $_POST['pass']; //パスワード

$data = array(
  'post_author'  => 1, // 投稿者ID 未設定の場合投稿者名なしになる。
  'post_status'  => 'publish', // 投稿状態
  'post_title'   => $_POST['title'],
  'post_content' => $_POST['content'],
);
$honbunlst  = mb_split( ",", $_POST['honbun'] );
$katsuyolst = mb_split( ",", $_POST['katsuyo'] );
$hinshilst  = mb_split( ",", $_POST['hinshi'] );
//本文、品詞、活用を一つずつカスタムフィールドとして登録する
for( $i=0; $i<count($honbunlst); $i++ ){
  $data['custom_fields'][] =
    array( 'key' => 'honbun', 'value' => $honbunlst[$i] ); 
  $data['custom_fields'][] =
    array( 'key' => 'katsuyo', 'value' => $katsuyolst[$i] ); 
  $data['custom_fields'][] =
    array( 'key' => 'hinshi', 'value' => $hinshilst[$i] ); 
}

$status = $client->query(
  "wp.newPost", //wp.newPostは、新規投稿
  1, // blog ID: 通常は1、マルチサイト時変更
  $user, // ユーザー名
  $pass, // パスワード
  $data  //追加するデータ
);

if(!$status){
  $res = array (
    'status' => 'error',
    'msg' => $client->getErrorMessage(), 
    'code' => $client->getErrorCode(),
  );
  echo json_encode( $res );  //JSONで返す
  return;
}
$post_id = $client->getResponse(); //返り値は投稿ID
$res = array(
  'status' => 'ok',
  'postid' => $post_id,
);
echo json_encode( $res );  //JSONで返す

mecabのテキストを読み込んで「。」ごとに本文と品詞・活用のデータを抽出しpost.phpを呼び出すC#を作成する。

C#の全部のソースは下記参照してください。

masatoru/xmlrpcsample · GitHub

CreateTextCore.cs(抜粋)
PostStatus postHonbun (string title, List<string> honbunlst, List<string> hinshilst, List<string> katsuyolst)
{
  try {
     string url = string.Format ("{0}/xmlrpc/post.php", url_);  //上記で作成したpost.phpへPOSTする
    //Console.WriteLine("POST={0}",url);
    var client = new System.Net.Http.HttpClient ();

  Dictionary<string, string> dict = new Dictionary<string, string>{
  { "user", user_ },//ユーザー名
  { "pass", pass_ },//パスワード
  { "title", title },//タイトル
  { "content", string.Join("",honbunlst.ToArray())  },//本文
  //mecabでばらした本文、品詞、活用形はカンマ区切りでPHPに渡す
  //PHP(post.php)側で配列で受け取ってカスタムフィールドとして登録する
  { "honbun", string.Join(",",honbunlst.ToArray()) },
  { "hinshi", string.Join(",",hinshilst.ToArray()) },
  { "katsuyo", string.Join(",",katsuyolst.ToArray()) },
  };

  //Dictionaryの値の文字列が長いとエラーになるので注意
  var content = new FormUrlEncodedContent (dict);       
  var response = client.PostAsync (url, content).Result;

  string json = response.Content.ReadAsStringAsync ().Result;
  return Newtonsoft.Json.JsonConvert.DeserializeObject<PostStatus> (json);
  } catch (Exception ex) {
    throw new Exception ("POSTできない MSG=" + ex.Message);
  }
}

品詞分解してWordPressで検索するまで(その1、mecab編)

古典のテキストをmecabで品詞分解するところまでやります。

mecabのインストール

まずは形態素解析をするためにmecabをインストール。

$ brew install mecab
$ brew install mecab-ipadic

動作確認。

$ mecab
おでんにはんぺんをいれるかなやみます  <==入力してEnter(またはコピペ)
おでん   名詞,一般,*,*,*,*,おでん,オデン,オデン
に 助詞,格助詞,一般,*,*,*,に,ニ,ニ
はんぺん    名詞,一般,*,*,*,*,はんぺん,ハンペン,ハンペン
を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
いれる   動詞,自立,*,*,一段,基本形,いれる,イレル,イレル
か 助詞,副助詞/並立助詞/終助詞,*,*,*,*,か,カ,カ
なやみ   動詞,自立,*,*,五段・マ行,連用形,なやむ,ナヤミ,ナヤミ
ます  助動詞,*,*,*,特殊・マス,基本形,ます,マス,マス
EOS

設定ファイルの場所。

vim /usr/local/Cellar/mecab/0.996/etc/mecabrc

出力形式を変更できる。

$ mecab -O wakati
おでんにはんぺんをいれるかなやみます
おでん に はんぺん を いれる か なやみ ます 
  • よみ
$ mecab -O yomi
おでんにはんぺんを入れるか悩みます
オデンニハンペンヲイレルカナヤミマス

古典の辞書を取得する

下記から中古和文用の辞書をダウンロード。

UniDic/中古和文UniDic - 言語データベースとソフトウェア

これを解凍して/usr/local/unidic-mecab/にコピー。

適当にテキストを持ってくる

青空文庫から土佐日記のテキストをダウンロード。

図書カード:土佐日記

Shift-JIS形式なのでこれをUTF-8形式で保存。

mecabで変換する

先ほどの中古和文の辞書に切り替えて、ダウンロードしたテキスト(tosa_nikki.txt)を変換する。 -dオプションを使わないで上記の設定ファイルを切り替えてももちろん可。

$ mecab -d /usr/local/unidic-mecab/ ./tosa_nikki.txt  -o ./tosa_hinshi.txt

変換結果(tosa_hinshi.txt)。

男  名詞,普通名詞,一般,*,*,*,オトコ,男,男,オトコ,オトコ,和,男,オトコ,オトコ,オトコ,*,*,*,*,*,*,3,C2,*
も 助詞,係助詞,*,*,*,*,モ,も,も,モ,モ,和,も,モ,モ,モ,*,*,*,*,*,*,*,"動詞%F2@-1,形容詞%F4@-2,名詞%F1",*
す 動詞,非自立可能,*,*,文語サ行変格,終止形-一般,スル,為る,す,ス,ス,和,す,ス,ス,ス,*,*,*,*,*,*,1,C4,*
なる  助動詞,*,*,*,文語助動詞-ナリ-伝聞,連体形-一般,ナリ,なり-伝聞,なる,ナル,ナル,和,なり,ナリ,ナリ,ナリ,*,*,*,*,*,*,*,"名詞%F2@1,形容詞%F2@-1動詞%F2@0",*
日記  名詞,普通名詞,一般,*,*,*,ニッキ,日記,日記,ニッキ,ニッキ,漢,日記,ニッキ,ニッキ,ニッキ,*,*,*,*,*,*,0,C2,*
...

次はこのテキストをC#で読み込んでWordPressに投げるとこまでをやります。

参考記事

Ruby - Macにmecabインストール - Qiita

バイナリファイルを文字列でサーバーへ転送する

バイナリファイルを添付でなく文字列でサーバーへ転送する方法を調べたのでメモ。

バイナリファイルを文字列に変換するのはunpackを使用する。

$str = unpack("H*", $binary);

試しにZIPファイルを読み込んで文字列に変換してみる。

$binary = file_get_contents('sample.zip');
$str = unpack("H*", $binary);
echo $str;

こんな感じ。

504b0304140008000800a6b86a420000000000000000000000000800 10006c6973742e786d6c55580c006fe6a95418933c ...略

これをバイナリに戻すのは、

$binary_string = pack("H*" , $str[1]);  //配列になっているので注意

これをファイルに保存すれば復元される。

if ( !$handle = fopen('new.zip', 'w') ){
  echo "Cannot create file";  //権限注意(777とか)
  exit; 
}
if ( fwrite($handle, $binary_string ) === FALSE ){
  echo "Cannot write file";
  exit;
} 
fclose( $handle );

ここまでできればPOSTでバイナリの文字列を渡せば転送できるはず。

次はこれを使ってC#からサーバーへバイナルファイルを転送してみる。

参考: バイナリ データの処理

Excel/C#でdynamic型からWorksheet型へキャストができない

はまったのでメモ。
ExcelC#で扱ってて.Net Framework4.0に上げたら、

Workbook book;
...
((Worksheet)book.Sheets[1]).SaveAs(path);

コンパイル通らないけど、

book.(Sheets[1] as Worksheet).SaveAs(path);

は通る。

error CS1969: 動的な式のコンパイルに必要な 1 つ以上の型が見つかりません。参照が指定されていることを確認してください。

そもそもキャストしないでも動くはずなのだけど、SheetとWorksheetと_Worksheetの型があるからこれが原因でキャストが必要なのか?
dynamicの仕組みがよくわからないのでまた後日調べる。

参考:
読ませてもらったけど難しい。
Excel遅延バインディング : ヒロの趣味ブログ

HTTPWebRequest.Createがネットワーク上で動かない(ことがあるらしい)

HTTPWebRequest.Createが動作せずどっぷりはまってしまったのでメモ。

System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)
  System.Net.WebRequest.Create("http://www.yahoo.co.jp");

これを実行すると例外が発生。

以下が出力されたエラー。

Message='system.net/defaultProxy' 構成セクションで指定された Web プロキシの作成中にエラーが発生しました。 
data=System.Collections.ListDictionaryInternal Source=System StackTrace= 
場所 System.Net.Configuration.DefaultProxySectionInternal.GetSection()
場所 System.Net.WebRequest.get_InternalDefaultWebProxy()
場所 System.Net.HttpWebRequest..ctor(Uri uri, ServicePoint servicePoint)
場所 System.Net.HttpRequestCreator.Create(Uri Uri)
場所 System.Net.WebRequest.Create(Uri requestUri, Boolean useUriBase)
場所 System.Net.WebRequest.Create(Uri requestUri)
場所 System.Net.SafeCloseSocketAndEvent.CreateWSASocketWithEvent(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, Boolean autoReset, Boolean signaled)
場所 System.Net.NetworkAddressChangePolled..ctor()
場所 System.Net.AutoWebProxyScriptEngine.AutoDetector.Initialize()
場所 System.Net.AutoWebProxyScriptEngine.AutoDetector.get_CurrentAutoDetector()
場所 System.Net.AutoWebProxyScriptEngine..ctor(WebProxy proxy, Boolean useRegistry)
場所 System.Net.WebProxy.UnsafeUpdateFromRegistry()
場所 System.Net.WebProxy..ctor(Boolean enableAutoproxy)
場所 System.Net.Configuration.DefaultProxySectionInternal..ctor(DefaultProxySection section)
場所 System.Net.Configuration.DefaultProxySectionInternal.GetSection() msg=無効な引数が提供されました。<br />

プロキシは設定してないし、無効な引数ってのはArgumentExceptionかと調べたけどそれも違う。

そしたらなんてことはないプログラムを動作させているマイドキュメントのフォルダがネットワーク上にあり、これをローカルに移動したらまさかまさか動いた。

シンクライアントなので権限が足りないのかそこらへんが理由っぽい(そこまでつきとめられず)。

参考にしたサイト:

WebRequest.Create defaultproxy exception - Google 検索

マイクロソフトの仕様なのかバグなのか。

追伸:Xenappとかシンクライアントってほんと嫌い。