C#でstringに格納されているCSVを処理する

  • ファイルからCSVを読み込む例は多かったけどstringに格納されたCSVの処理があんまりなかったのでメモ。

対象文字列の処理

  • _msgというstringに入ってきた複数行のCSVデータを1行づつバラす。
    • Split()は文字列指定ができる。
string[] lines = _msg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
  • CSVを処理するのにstreamが都合がいいのでstringを変換する
string[] lines = _msg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var line in lines.Select((v, i) => new { v, i }))
{
    using (Stream stream = new MemoryStream(Encoding.Default.GetBytes(line.v)))
    {
        // CSV処理
    }
}

CSVの処理

  • stringのSplit(',')だと当然ながらカラムの中にカンマが出てきたらずれてしまうのでMicrosoft.VisualBasic.FileIO.TextFieldParserを使う。
using Microsoft.VisualBasic.FileIO;

TextFieldParser parser = new TextFieldParser(stream, Encoding.GetEncoding("shift_jis"));
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
try
{
    string[] csvData = parser.ReadFields();
    // CSV処理
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
}

サンプル

  • _msgには1行目にヘッダ、2行目以降にCSVデータが入ってくる想定。
    • コンソールアプリから実行した別のコマンドの結果をパースする想定でEncodingを指定。
using Microsoft.VisualBasic.FileIO;

_msg = FooMethod();
string[] lines = _msg.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);

foreach (var line in lines.Select((v, i) => new { v, i }))
{
    using (Stream stream = new MemoryStream(Encoding.Default.GetBytes(line.v)))
    {
        TextFieldParser parser = new TextFieldParser(stream, Encoding.GetEncoding("shift_jis"));
        parser.TextFieldType = FieldType.Delimited;
        parser.SetDelimiters(",");

        try
        {
            if (line.i == 0)
            {
                string[] csvHeader = parser.ReadFields();
            }
            else
            {
                string[] csvData = parser.ReadFields();
                foreach (var item in csvData.Select((v, i) => new { v, i }))
                {
                    Console.WriteLine(string.Format("  {0} : {1}", csvHeader[item.i], item.v));
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

.NETなのに、意外とシャキッと処理できないもんだよなぁ。

Groovyをプロキシ環境下で使う

よく忘れるのでメモ

  • 特にhttpsとかno_proxyの書き方とかすぐ忘れるし。
  • 以下の例は実際にはどれも1行で記述します。コピペしてもそのまま実行できません!

コマンドライン

$ groovy -DproxyHost=proxy.example.com -DproxyPort=8080
         -Dhttps.proxyHost=proxy.example.com -Dhttps.proxyPort=8080
         -Dhttp.nonProxyHosts="localhost|192.168.*.*|10.*.*.*|*.example.com"
         hogehoge.groovy

環境変数

  • LinuxとかMacとか。
    • nonProxyHostsはちょっと自信なし。
$ export JAVA_OPTS="-DproxyHost=proxy.example.com -DproxyPort=8080
          -Dhttps.proxyHost=proxy.example.com -Dhttps.proxyPort=8080
          -Dhttp.nonProxyHosts=localhost|192.168.*.*|10.*.*.*|*.example.com"
  • Windows
    • 「"」ダブルコーテーションの位置に注意!
      • Windowsでは全体を囲む必要はないけど「*」を使うときは値を囲んであげる。
> set JAVA_OPTS=-DproxyHost=proxy.example.com -DproxyPort=8080
       -Dhttps.proxyHost=proxy.example.com -Dhttps.proxyPort=8080
       -Dhttp.nonProxyHosts="localhost|192.168.*.*|10.*.*.*|*.example.com"

framesetを使った画面でIEだけ隙間ができる

  • IEだけ上下のframeの間に2pxの隙間ができてました。

対応

  • 元々以下のようになっていました。
<frameset rows="90px,*" frameborder="0">
    <frame src="test1.html" name="test1" />
    <frame src="test2.html" name="test2" scrolling="no" />
</frameset>
  • 以下のように修正した所直りました。
<frameset rows="90px,*" frameborder="0" border="0" framespacing="0">
    <frame src="test1.html" name="test1" frameborder="0" marginheight="0" marginwidth="0" />
    <frame src="test2.html" name="test2" scrolling="no" frameborder="0" marginheight="0" marginwidth="0" />
</frameset>
  • 参考

Controlling Frame Borders in Internet Explorer and Netscape

Gitでサブディレクトリを切り出して別リポジトリにする

  • SVNから移行したリポジトリだとモジュールやライブラリ、サブプロジェクトが全て1つのリポジトリに入っていることが多い。
    • Gitだと扱いくいのでリポジトリを分けたいことが結構ある。
    • SVNのTagやBranchは任意のサブディレクトリから作れるので分離するときは注意すること。

サブディレクトリをトップレベルに昇格させてリポジトリを分ける

SVNリポジトリでやってみる

  • SVNをCloneする。
    • TagやBranchもいらないものがたくさんあるので必要な物以外は消したほうが良い。
    • ベタだけどいらないTagとBranchの一覧ファイル(例ではaaa, bbb)を用意して削除してます。
      • 一覧を作っているTag/Branchだけ消したファイルを作って、そのファイルを元にコマンドで削除。
$ git svn clone -s hoge
$ cd hoge
$ 

$ git tag > aaa
$ vi aaa
$ cat aaa | xargs git tag -d

$ git branch > bbb
$ cat bbb | xargs git branch -D

Gitのフィルタコマンドでディレクトリ構成を変更。

$ git filter-branch --subdirectory-filter src/SubProject -- --all

Ref 'refs/tags/subproject-1.2.1' was rewritten
WARNING: You said to rewrite tagged commits, but not the corresponding tag.
WARNING: Perhaps use '--tag-name-filter cat' to rewrite the tag.
WARNING: Ref 'refs/tags/subproject-2.0.0.1' is unchanged
  • なんかTagがらみで怒られるのでオプションを変えてもう一回実行。
$ git filter-branch --subdirectory-filter src/SubProject --prune-empty --tag-name-filter cat -- --all

新しいGitリポジトリを作ってPush

  • 念の為にゴミ掃除してから新しいリモートリポジトリを登録してPushします。
$ git gc --auto
$ git reflog expire --expire=now --all
$ git gc --prune=now
$ git remote add new_origin ssh://git@git.example.com:7999/newproject/subproject.git
$ git push -u new_origin --all && git push --tags
$ git remote remove new_origin

でかいSVNリポジトリでは微妙かも?

  • TagやBranchを削除してgit-gcしてもあまり小さくはなりませんでした。
    • おそらく履歴も削除しないとダメなのかと。ただ、歴史の長い大きなリポジトリだとやってられませんよね・・・。
  • 履歴についてはSVNリポジトリとしてまるっと移行して、切り出したいのは履歴無しで別リポジトリにして始めるというのもアリかと思います。
    • っていうか、そうしてるのもあります。

参考資料

Git - git-filter-branch Documentation

urashita.com

egulog.hatenablog.jp

GitでリモートリポジトリにPushした後でコミットをなかった事にしたい

revertでコミットを打ち消す事にする

  • 履歴を改編してpush -fすれば無かったことに出来るのでしょうがやりたくないのでrevertすることにしました。
    • ところがPullRequest運用で出来たMergeのコミットに対してSourceTreeから上手くrevert出来なかったのでブログに残しておきます。

エラー発生

  • 単純に取り消したい所を選んで右クリックで「コミット適用前に戻す」をしたらエラーになった。 f:id:gozuk16:20150715202341p:plain

    • git revert --helpでみると-mというのは-m parent-number, --mainline parent-numberとなっていてどうやらMergeのコミットの場合は戻るべき親が複数あるので位置を指定するらしいです。
  • SourceTreeのグラフ(樹形図)でも見えますけど、git log --oneline --graphとすると以下の様なものがでます。

*   7469d7e Merge pull request #2 from gozuk16/feature/2
|\
| * 60b8bb2 revert test 2
|/
* 6167dcb Revert "revert test 2"
* 9d2615c revert test 2
*   f4466bb Merge pull request #1 from gozuk16/feature/1
|\
| * e98d717 revert test 1
|/
* dd65d81 ローカルで修正
* e8a97f6 Initial commit
  • 7469d7eをrevertしたいとすると、どちらが親か決めないといけないので-m 1というように親を指定します。
    • 1と言うのは60b8bb26167dcbのうち6167dcbを指定していることになります。
      • グラフの左側から1, 2, 3・・・と数えるらしいです。

revert

  • SourceTreeではパラメータが指定できなかったので端末(コンソール)を押してコマンドでやります。
    • 複数revertするときは新しいコミットから遡っていきます。
    • 今回は、dd65d81に戻りたいので7469d7ef4466bbの2つを打ち消します。
$ git revert -m 1 --no-edit 7469d7e
[master 62644c2] Revert "Merge pull request #2 from gozuk16/feature/2"
 1 file changed, 1 deletion(-)
$ git revert -m 1 --no-edit f4466bb
[master b1e918e] Revert "Merge pull request #1 from gozuk16/feature/1"
 1 file changed, 5 insertions(+), 6 deletions(-)
  • SourceTreeでみると62644c2b1e918eの打ち消しコミットが2つで来ています。
    • 一番新しい打ち消しコミットのb1e918eと元に戻りたいdd65d81を選択すると差異が無いことがわかります。 f:id:gozuk16:20150715202401p:plain

rebase

  • 普段はめったにrebaseしないのですが、さすがに打ち消しコミットが2つあると後でわかりにくいのでrebaseします。
    • SourceTreeで打ち消しコミットの1つ前(7469d7e)を選択して右クリックすると「7469d7eの子を対話式でリベース」(7469d7eの子とインタラクティブなリベースを行う)と出ます。
    • 新しい方のコミットを選択して、「過去を含めてsquash する」(前のコミットとスカッシュ)を押すとコミットがまとまります。
    • 「メッセージを編集」を選んで適当にメッセージを書きます。
    • OKすると2つあった打ち消しコミットが1つにまとまります。 f:id:gozuk16:20150715203932p:plain
  • Pushしてお終い。

感想

  • ちゃんと履歴を残しつつ好きな場所に戻れるとか、Git便利だなー。
  • どうでもいいことですが、SourceTreeのMac版とWindows版で日本語訳変えるのやめて欲しい。
    • というか日本語訳とコマンドが紐付かなくてちょっと不安になることもある。どのコマンドを使っているのか日本語訳にも付けてくれると嬉しいかも。

Homebrewが使えなくなった

  • yosemiteに上げた時かその後のアップデートかわからないけどbrewが使えなくなってた。

エラー発生

$ brew update
/usr/local/bin/brew: /usr/local/Library/brew.rb: /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby: bad interpreter: No such file or directory
/usr/local/bin/brew: line 21: /usr/local/Library/brew.rb: Undefined error: 0
  • rubyのバージョンを確認したらエラーが出てるのとは違う。
$ ruby -v
ruby 2.0.0p481 (2014-05-08 revision 45883) [universal.x86_64-darwin14]
  • エラー出してるファイル覗いてみたら1.8って書いてある。
$ view /usr/local/Library/brew.rb
#!/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -W0

再インストール

  • 1.8をCurrentに書き換えたけどやっぱりダメだったので入れなおす。
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
It appears Homebrew is already installed. If your intent is to reinstall you
should do the following before running this installer again:
    rm -rf /usr/local/Cellar /usr/local/.git && brew cleanup
  • エラーで入れられないのでメッセージに従ってみる。
$ rm -rf /usr/local/Cellar /usr/local/.git && brew cleanup
/usr/local/bin/brew: /usr/local/Library/brew.rb: /System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby: bad interpreter: No such file or directory
/usr/local/bin/brew: line 21: /usr/local/Library/brew.rb: Undefined error: 0
  • brewコマンドが動かないので1.8のところをCurrentにしてcleanだけ流してみる。
$ vi /usr/local/Library/brew.rb
#!/System/Library/Frameworks/Ruby.framework/Versions/Current/usr/bin/ruby -W0
$ brew cleanup
  • うまく行ったので、もっかい再インストール!
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
==> This script will install:
/usr/local/bin/brew
/usr/local/Library/...
/usr/local/share/man/man1/brew.1

Press RETURN to continue or any other key to abort
==> Downloading and installing Homebrew...
remote: Counting objects: 3608, done.
remote: Compressing objects: 100% (3450/3450), done.
remote: Total 3608 (delta 33), reused 673 (delta 19), pack-reused 0
Receiving objects: 100% (3608/3608), 2.88 MiB | 981.00 KiB/s, done.
Resolving deltas: 100% (33/33), done.
From https://github.com/Homebrew/homebrew
 * [new branch]      master     -> origin/master
HEAD is now at 5b7f4f2 mysql-connector-odbc: add 5.3.4 bottle.
==> Installation successful!
==> Next steps
Run `brew help` to get started
$ brew update

でけた〜。

Mac版LimeChatの見た目をカスタマイズする

  • Windows版のLimeChatGUIで細かく設定できるのですが、Mac版には設定画面がなかったのでこの辺を見ながらやってみました。
    • 設定ファイルをいじるのは別に苦じゃないし、CSSなのはわかりやすいと思う。 naopr.hatenablog.com naoty.hatenablog.com

カスタマイズ用のファイルを準備

  • もともとSpring Nightを使っていたのでカスタマイズ用のフォルダに元ファイルを別名でコピります。
    • 元ファイルフォルダ:/Applications/LimeChat.app/Contents/Themes
    • カスタマイズ用フォルダ:/Users/username/Library/Application Support/net.limechat.LimeChat-AppStore
  • 元ファイル用のフォルダは「パッケージの内容を表示」で開けます。
  • CSSyamlファイルをセットでコピります。

カスタマイズ

  • とりあえずjoinとかquitのメッセージがうざいので表示しないようにCSSへ以下を追加。
.line[type=join] { display: none; }
.line[type=quit] { display: none; }
.line[type=mode] { display: none; }
.line[type=part] { display: none; }
.line[type=nick] { display: none; }
  • それから時間の色をもう少し地味にするのに.timeのcolorを修正。
.time { color: #888; }

これだけだけど結構スッキリしたので、満足。