echo("備忘録");

IT技術やプログラミング関連など、技術系の事を備忘録的にまとめています。

Githubにファイルをpushする際のトラブルシューティング

先日、フリーランス向けの「ふるさと納税可能額算出ツール」という
ツールをGithubに公開しました。

github.com

ただ、その際に色々ハマったことがありましたので、
備忘録も兼ねて対策方法を記載しておきます。


■SourceTreeが重いときの対処方法
Git操作系のGUIツールで有名な「SourceTree」ですが、このSourceTreeが
異常に重いことがあります。

SourceTree:https://ja.atlassian.com/software/sourcetree

「内蔵GitとシステムGitのバージョン差異」に起因する何かが
原因らしいですが、調べたところ、下記のような対処方法があるようです。

1. 一部ドライバを削除する

AMD Radeon graphics driver」というドライバを削除したり、
更新したら改善した、というケースがあるようです。
※もちろん、これやったから100%直る訳ではない。

Windows10 64bit でgitBashやSourceTreeがやたら遅い 重い


2. SourceTreeで「システムGitを使う」設定に変更する

SourceTreeの設定で「内蔵Gitを使う」設定になっている場合、
重くなるケースがあるようです。

その場合、
1. Gitの最新バージョンをインストールする。
2. SourceTreeの設定を「システムGitを使う」

とすると、改善する場合があるようです。(僕は直りませんでしたが...)

3. 諦めて、CUIベースで操作する

正直な話、これが一番確実な方法では?と思います。
Gitのコマンド自体はそんなに多いわけではないし、リポジトリ
クローンした後の基本的な、

  • ステージング
  • ローカルコミット
  • リモートpush

という作業だけなら、テンプレートのスクリプトファイルを作って、適宜
必要な箇所だけ修正し、そのスクリプトを実行すれば、毎回コマンドを入力する
手間も省けますし。

何より、無理にSourceTreeの調査に時間を充てるくらいなら、その方が
よっぽど時間を有効に使えるのでは?というのが最大の理由です。


■.gitignoreファイルが作成できない

.gitignore(管理しないファイルの設定ファイル)ファイルですが、普通に
Windowsエクスプローラ上で新規作成しようとしても、作成できません。
(「ファイル名を入力してください」とエラーになる。)
※「gitignore」を拡張子として認識してしまうため。


これを回避するには、

1. ファイル名を「.gitignore.」と入力して、新規ファイルを作成する。
(最後に「.」を付ける)
2. 「拡張子が付いていない...」というメッセージが表示されるので、
「はい」をクリックする。

これでエクスプローラ上でも「.gitignore」ファイルが作成できます。

というか、ファイル作成はGitHub上で行うのが無難かも。


■*.mdファイルのMarkdown記法がリモートリポジトリ上で効いてない場合の対処方法

ReadMeなどの*.mdファイルを更新した際、何故か途中から「Markdown記法が
全く反映されない」という現象が発生しました。

原因は、おそらく途中で設定ファイルの「改行コード」の設定を
手動で変えたことに起因する何か(内部コードがおかしくなった、等)だと
思われます。(ただ、Visual Studio CodeMarkdownビューアーでは、
全く問題なかったんですよね…)

これ自体の解決としては、単純に

  • Markdownが反映されない部分以前の空白文字を削除する
    (場合によっては書いた内容も)

で解決できますが、文字コードの設定は結構重要な部分なので、まとめました。

  • Github上で表示するファイル(*.mdファイルなど)は、改行コードは
    「LF」にする。
  • Gitのインストール時の改行コード設定に注意


f:id:Makky12:20180818073602p:plain

たいていインストールの設定って、デフォルトのまま「次へ」を連打して
しまいがちですが、(Gitは英語表記なのでなおさら)、
Gitの「改行設定」だけは注意が必要です。

上記画像では、上から順に

  • チェックアウト時はLF→CRLFに変換/push時はCRLF→LFに変換
  • チェックアウト時は変換なし/push時はCRLF→LFに変換
  • チェックアウト時/push時ともに変換なし

なんですが、真ん中の「チェックアウト時は変換なし/push時は
CRLF→LFに変換」にしておくのが、無難のようです。

気をつけて!Git for Windowsにおける改行コードqiita.com

※一番下の「変換無し」設定は、上記画像でもわかる通り、クロス
 プラットフォームの環境では非推奨なので、選ばないほうが無難かも。
※「変換無し」設定の場合、ツール側で設定などを行う必要があります。
 VS Codeなら「検索/置換」ウィンドウの「正規表現を使う」オプションを
 ONにすれば、改行コードでの検索/置換が可能です。
※ただ「変換あり」「変換無し」それぞれにメリット、デメリットがあり、
 一概にはどちらが良い、とも言えないようです。
qiita.com

以上、僕がGitHubにファイルをpushする際に遭遇したトラブル、および
その解決策でした。


てか、また前回からかなり間が開いてしまった...

業務都合だったり、あとメンタルの調子を崩したり、色々あったから
なのですが、やはりもう少し更新頻度を上げないと。
別に書きたいネタはそれなりにあるので、別にプログラミングのネタに
こだわらなくてもいいから、もう少し更新頻度を上げないといけませんね。
(こればっか)

【VBA】ファイルをクリップボードにコピーする(Win32API不使用)

超久しぶりの記事&超久しぶりにVBAの記事。
(てか、VBAって時点でネタ切れ感が…)

「(何かの)ファイルをクリップボードにコピーする」という場合の処理。
(要はファイルのコピー)

VBAクリップボードにコピー...という場合、よくあるのは「MSForms.DataObject」を使用する方法。

ただこれだと「テキスト」や「bitmap画像」はうまくいくけど「ファイルそのもの」のコピーはうまくいかない。
(VBAだから、Excel上でやり取りするデータ、という前提なのかも)

あと、Win32API関数を使用しても出来るけど、何個も関数を呼ぶ必要があるので、できればもっと単純にしたい。
(OpenClipboard()→EmptyClipboard()→SetClipboardData()→closeClipBoard()という流れ)

ということで、色々調べてたら、こんな感じで実装できた。
※簡略化のため、エラー処理とかはかなり端折ってます。
※dir_pathは対象ファイルの格納フォルダパス、file_nameはファイル名です。

Dim objShell As object
Dim objDir As object

Set objShell = CreateObject("Shell.Application")
Set objDir = objShell.Namespace(CVar(dir_path))
If (Not objDir Is Nothing) Then

    Dim objFile As object
    Set objFile = objDir.ParseName(file_name)

    For Each verb In objFile.Verbs
        If verb.Name = "コピー(&C)" Then
            verb.doit
            Exit For
       End If
    Next

    Set objFile = Nothing
End If

Set objDir = Nothing
Set objShell = Nothing

※参考:『ファイルをコピーしクリップボードに格納した状態』(田吾作) エクセル Excel [エクセルの学校]

処理の流れとしては

  1. Shell.Applicationオブジェクトを作成して
  2. 1のNameSpaceメソッドでFolderオブジェクト、またそのParseNameメソッドでFolderItemオブジェクトを取得して
  3. 2のVerbsコレクションからファイルのメニュー一覧を取得して「コピー(&C)」なら、それを実行する

という感じ。

ただ、2の「NameSpaceメソッド」で、フォルダパスをVariant型で渡さないとエラーになるので注意。
(まあ、公式ドキュメントにはちゃんと書いてあるけど...)

ただ、今回はコピーのみが必要だったから「貼り付け」の処理は実施してない。
機会があったら、調べてみようと思います。

てか、次はXamarinとかPythonとか、あとReact、Vue.js、Ionicなんかの触りの部分もやってみたいな。

【Xamarin.Forms】遭遇したエラーと対応集

Xamarin.Formsを触り始めてしばらく経ちますが、その中で僕が遭遇したエラー、及びその対処法になります。
なお、一般的なエラーについては、下記ページを参照。

※@nuits_jpさんのページ
Xamarin for Visual Studioインストール後、Androidプロジェクトをデバックしようとしたら配置エラーが発生した場合の対処法 - Qiita
Xamarin for Visual Studio スタートアップ トラブルQA集 - nuits.jp blog

※エクセルソフト 田淵さん(@ytabuchi)のページ
Xamarin FAQ(小技集、またの名をバッドノウハウ) - Xamarin 日本語情報

※僕がiPhone持ってないので、Androidのみ記載しています。すいません...


■ビルド時に「The $(TargetFrameworkVersion) for Xamarin.Forms.Platform.dll is greater than the $(TargetFrameworkVersion) for your project」というメッセージが表示される

【原因】
「ターゲットバージョン」で指定されているOSのバージョンが古すぎる。「ターゲットバージョン」は、最低限Xamarin.Forms.Platform.dllのOSのバージョンと同等かそれ以上である必要がある。

【対処方法】
[Androidマニフェスト]-[ターゲットAndroidバージョン]で、OSのバージョンを該当バージョンまで上げる。
※「SDKバージョンを使用した...」を選択している場合、[アプリケーション]-[Androidバージョンを使用したコンパイル]のOSバージョンを上げる。
デバッグで使用するデバイスのOSのバージョンが低い場合、「最小Androidバージョン」をそのデバイスに合わせればOK。


f:id:Makky12:20180422200239p:plain


■実行時に特定のメソッドで、NoSuchMethodErrorが発生する

【原因】
該当メソッドと、使用しているアセンブリ、またはデバイスのバージョン、及び互換性の問題。

【対処方法】
・使用しているアセンブリのバージョンが低い場合、Visual StudioAndroid SDK Managerなどで、最新バージョンに更新して、再度実行する。
デバッグに使用しているデバイスのOSバージョンが低い場合、更新できるなら更新する。(更新できない場合、別デバイスでの確認にする、あるいは該当メソッドのデバッグは諦めるしかない(かも))


■ビルド時に「前のバージョンの実行をサポートしていません。」というメッセージが表示される

【原因】
不明。
Visual Studioの更新を行った際に、何かの原因で発生することがある模様。

【対応方法】
ピンポイントでのベストな対応方法は不明。
今のところ「Visual Studioの修復or再インストール」しかないみたい...

【備考】
メッセージから「デバイスのOSを最新バージョンにすれば...」と思ってしまうが、最新バージョンにしてもこの現象は解決しない。(てか、ある程度前のバージョンは普通に動作するはずだし...)

参考ページ:Android - Xamarinのビルドに失敗。前のバージョンの実行をサポートしていません。(121632)|teratail


以上です。

【Xamarin.Forms】LabelにBorderを設定する

前回の記事同様、Style関連の内容です。

各種GUIで「Border(=境界線)」の太さや色などの設定、があると思います。
で、現在作成中のXamarin.Formsアプリで、同様の事をLabelで行おうとしたら...

Xamarin.FormsのLabelには「Border」プロパティがない!
※要は、枠線を表示できないということ。

まあ、ないものは仕方がないのですが、何とかやる方法はないか...ということで調べたら、以下の方法がありました。
参考:Xamarin.Forms で枠線付きのラベルを作る - clock-up-blog

1.LabelをFrame内に書く
→Frameの「OutlineColor」プロパティを使用すれば、枠線の色は指定できる。
 でも太さは指定できない。

2.Labelを2重Frameで囲む
→親Frameの「BackgroundColor」及び「Padding」を指定して、その中に子Frame&Labelを表示すれば、子Frame&Labelが表示されていない箇所が(見た目は)枠線のように表示される。
ただ、複数の枠線付きLabelを表示させたい場合、すべてに2重Frameを用意するのは、コーディングが面倒かも...

3.Buttonで代用する。
→Labelと違い、Buttonには「Border」関連のプロパティがあるので、それならButtonで代用しちゃえ、という方法。
 Labelへのこだわりがなければ、正直これが一番手っ取り早い。(ただ「Labelの枠線」という趣旨からは外れるけど...)
 
てか、なぜButtonにはBorderがあって、Labelにはないのか…


最後に、ソースコードと実際の画面をば。

    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="ButtonRedStyle" TargetType="Button">
                <Setter Property="TextColor" Value="Black" />
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="VerticalOptions" Value="Center" />
                <Setter Property="BackgroundColor" Value="Red" />
                <Setter Property="BorderColor" Value="Black" />
                <Setter Property="BorderWidth" Value="2" />
                <Setter Property="BorderRadius" Value="0" />
            </Style>
            <Style x:Key="FrameLabelStyle" TargetType="Label">
                <Setter Property="FontSize" Value="20" />
                <Setter Property="HorizontalOptions" Value="Center" />
                <Setter Property="VerticalOptions" Value="Center" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <StackLayout HeightRequest="500">
            <Label Text="1:LabelをFrame内に書く" />
            <Frame WidthRequest="110"
                HeightRequest="80"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                Padding="0"
                OutlineColor="#f00" >

                <Label Text="あああ" Style="{StaticResource FrameLabelStyle}" TextColor="Black" />
            </Frame>

            <Label Text="2:Labelを2重Frameで囲む" />
            <Frame WidthRequest="106" 
                   HeightRequest="76" 
                   HorizontalOptions="Center" 
                   VerticalOptions="Center"
                   Padding="2"
                   BackgroundColor="#f00"
            >
                <Frame Padding="0"
                     BackgroundColor="#000"
                     VerticalOptions="Fill"
                     HorizontalOptions="Fill">
                    <Label Text="いいい" Style="{StaticResource FrameLabelStyle}" TextColor="Yellow" />
                </Frame>
            </Frame>

            <Label Text="3:Buttonで代用する" />
            <Button x:Name="button_red" Text="ううう" Style="{StaticResource ButtonRedStyle}" />
        </StackLayout>
    </ContentPage.Content>

f:id:Makky12:20180412212724j:plain

まだまだXamarinは発展途上、これからが楽しみですね。
(精一杯のフォロー)

【Xamarin.Forms】コントロールのスタイルを設定する

Xamarin.Formsでラベルやボタンなどのスタイルを設定する方法。
(Windows Formなら「プロパティ」で簡単に設定できるんだけど...)

XAMLの場合

「ResourceDictionary」を使用する。

    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="ButtonRedStyle" TargetType="Button">
                <Setter Property="TextColor" Value="Black" />
                <Setter Property="BackgroundColor" Value="Red" />
                <Setter Property="BorderColor" Value="Black" />
                <Setter Property="BorderWidth" Value="2" />
                <Setter Property="BorderRadius" Value="0" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <StackLayout>
            <Button x:Name="button_red" Text="Red" Style="{StaticResource ButtonRedStyle}" />
        </StackLayout>
    </ContentPage.Content>

結果:
f:id:Makky12:20180412102843j:plain

ResourceDictionaryでスタイル及び「x:Key」を設定して、それをコントロール側で「style="{StaticResource xxx}"」で参照する。

C#で直書きする場合

            var buttonBlueStyle = new Style(typeof(Button))
            {
                Setters = {
                    new Setter { Property = Button.TextColorProperty, Value = Color.White },
                    new Setter { Property = Button.BackgroundColorProperty, Value = Color.Blue },
                    new Setter { Property = Button.BorderColorProperty, Value = Color.Black },
                    new Setter { Property = Button.BorderWidthProperty, Value = 2 },
                    new Setter { Property = Button.BorderRadiusProperty, Value = 0 },
                }
            };

            var blueButton = new Button
            {
                Text = "Blue",
                Style = buttonBlueStyle,
            };

            var stackLayout = new StackLayout
            {
                Children =
                {
                    blueButton
                },
            };
            
            this.Content = stackLayout;

結果:
f:id:Makky12:20180412102836j:plain

C#の場合は「Style」クラスで普通に参照する。

ちなみに、これはページ毎に設定してますが、全ページ共通のスタイルにする場合、AppクラスにStyleを定義すれば、共通スタイルとして定義できる。
参照:Xamarin.Forms で Style を利用する - Xamarin 日本語情報

※公式サイト(Xamarin Documentation - Xamarin | Microsoft Docs)ではC#(コードビハインド)で書かれているので、コードビハインドで記述するのが良いのかも...


昔に比べて、だいぶ良くなってきたとはいえ、まだまだXamarinは改良してほしい点が多いですね。

【python】pythonでExcelを操作する その2【brainf*ck】

前回Pythonで簡単なExcel操作について書きました。
今回はもうちょっと踏み込んだものを、と考えた結果「brainf*ck」のインタプリタPythonで作る事にしました。

ちなみに「brainf*ck」とは...

Brainfuck(ブレインファック)は難解プログラミング言語のひとつ。なお名称に卑語が含まれるため、Brainf*ckなどと表記されることがある。
(Wikipediaより)

だそうです。

ちなみに、下記命令文字列は「Hello,Python」と出力するものなのですが...なんのことやら、さっぱりですね。

 +++++++++[>++++++++>+++++++++++>+++++<<<-]>.>++.+++++++..+++.>-.<<++++++++.>>>+++++++++++[>+++++++++++<-]>.-----.<++++[>---<-]>.<<<.-.

なお参考としては、先述のWikipedia(https://ja.wikipedia.org/wiki/Brainfuck)、

また実際の動きを見たい場合、以前ネットニュースでも話題になった、t-kihiraさんの動画が大変分かりやすくてよいと思います。
(こちらはjavascriptで作成してます。てかHTMLやDOM操作など全込みで1時間は凄すぎ!)
nicotter.net

どこをExcelと連携するか

ですが、brainf*ckには

  • 命令文字列(><+-.,[])の読み込み
  • メモリへの書き込み

があるので、前者をExcelシートから読み込み、後者をExcelシートに書き込もうと思います。

共通変数は?

共通変数(≒クラス変数)ですが、先述のWikipediaに、brainf*ckで管理が必要そうなものとして

  • 現在のポインタ
  • メモリの値(アドレスごと)

がありますので、これを共通変数にすればよいかと。

また、「メモリのアドレスの個数」あたりも共通変数にしとくと便利そうです。

あ、肝心のExcel関連(ブック・シート)も共通変数にしたほうが便利そうですね。

で、まあこんな感じかと。

import sys
sys.path.append([openpyxlの格納パス])  ##デフォルトで読み込み可能なら不要

import openpyxl as pyxl
from openpyxl import load_workbook

MEMORY = []  ##メモリの値(アドレス毎)  
POINTER = 0  ##現在のポインタ
MEMORY_LENGTH = 30  ##メモリのアドレスの個数
RESULT_STRING=""

##対象のブックとシート
WORK_BOOK = load_workbook('brainf_ck.xlsx')
WORK_SHEET = WORK_BOOK.get_sheet_by_name('Sheet1')


実際の読み書き処理

ですが、これは例えば

  • B1セルは命令文字列
  • B4~K6セルはメモリの値

というように決め打ちすれば、比較的楽ではないかと。

またメモリ書き込みは何回も呼び出すので、関数にしておきましょう。

で、コードとしてはこんな感じかな?
(てかpythonって、文字列の切り出しが'変数名[添字]'でいいんですね。
substring()とかいらないので、便利です。)

## 命令文字列の読み込み
command_string = str(WORK_SHEET['B1'].value)
## 命令文字列の書き込み関数
## valueは書き込む値(数値)
def writeMemoryToSheet(value):

    #global POINTER
    memory_string_length = len("000" + str(value))
    memory_string = ("000" + str(value))[memory_string_length -3:]

    row = 0
    col = (POINTER % 10) + 2

    if(POINTER <= 9):
        row = 4
    elif(POINTER >= 10 and POINTER <= 19):
        row = 5
    else:
        row = 6

    WORK_SHEET.cell(row=row, column=col).value = memory_string

命令文本体

で、肝心の命令文ですが、Wikipediaによると、

  • >: ポインタをインクリメントする。ポインタをptrとすると、C言語の「ptr++;」に相当する。
  • <: ポインタをデクリメントする。C言語の「ptr--;」に相当。
  • +: ポインタが指す値をインクリメントする。C言語の「(*ptr)++;」に相当。
  • -: ポインタが指す値をデクリメントする。C言語の「(*ptr)--;」に相当。
  • .: ポインタが指す値を出力に書き出す。C言語の「putchar(*ptr);」に相当。
  • ,: 入力から1バイト読み込んで、ポインタが指す先に代入する。C言語の「*ptr=getchar();」に相当。
  • [: ポインタが指す値が0なら、対応する ] の直後にジャンプする。C言語の「while(*ptr){」に相当。
  • ]: ポインタが指す値が0でないなら、対応する [ (の直後[1])にジャンプする。C言語の「}」に相当[2]。

ということですが、下2つ以外は、特に問題ないかと思います。
他の「brainf*ck作ったよ!」というサイトなどでも説明されていますが、

  • POINTERの値を加減する
  • MEMORY[POINTER]の値を加減する...

といった感じですね。

MEMORY[POINTER]の値を加減した場合、先程の関数でExcelにも値を書きます。
また、コンソールからの入力にも対応してあげなくてはなりません(=input()関数)
※chr(value)関数は、value文字コードを文字に変換する関数。
 逆にord(value)関数は、valueの文字を文字コードに変換する関数。

てかPythonって、switch case構文ないんですね...

   i = 0

    while i < len(command_string):

        char = command_string[i]

        if(char == ">"):
            POINTER += 1
            if(POINTER >= MEMORY_LENGTH):
                print("エラー:不正な\'>\'があります。")
                return
        elif (char == "<"):
            POINTER -= 1
            if(POINTER < 0):
                print("エラー:不正な\'<\'があります。")
                return
        elif(char == "+"):
            MEMORY[POINTER] += 1
            writeMemoryToSheet(MEMORY[POINTER])
        elif(char == "-"):
            MEMORY[POINTER] -=1
            writeMemoryToSheet(MEMORY[POINTER])
        elif(char == "."):
            RESULT_STRING += chr(MEMORY[POINTER])
        elif(char == ","):
            while True:
                input_char = input("半角英数1文字を入力してください。")
                if(len(input_char) != 1):
                    print("エラー:1文字ではありません。")
                else:
                    char_code = ord(input_char)

                    if(char_code < 0 or 127 < char_code):
                        print("エラー:半角文字ではありません。")
                    else:
                        MEMORY[POINTER] = char_code
                        writeMemoryToSheet(MEMORY[POINTER])
                        break
        i += 1


問題の下二つ

ですが、これは「'['や']'があったら、対応する']'や'['を見つける」処理が必要です。
この処理は関数にしてしまい、「対応する'['や']'の位置」は、リスト(他言語でいう配列)で管理すると楽です。

てな訳で、ソースはこちら。

## idxはcommand_string内での'['の位置
## target_stringはcommand_string。
## KAKKOは対応する位置を管理するlist(共通関数にする)

def checkKakkoRange(idx, target_string):

    for i in range(idx + 1, len(target_string)):

        kakko_count = 0
        check_char = target_string[i]

        if(check_char == "["):
            ## 2重以上の'['があったら、kakko_countを+1する
            kakko_count += 1
        elif(check_char == "]"):

            if(kakko_count == 0):
                ##kakko_countが0の場合の']'は、対応する']'である。
                KAKKO[idx] = i
                KAKKO[i] = idx
                break
            else:
                ##そうじゃない場合の']'は、対応する']'ではないので、kakko_countを-1する。
                kakko_count -= 1

で、先ほどの「命令文本体」のところに、こんな分岐処理を追加すればよいかと。

        if(char == ">")
            ## 中略
        elif(char == "["):
            ## 初回のみ、checkKakkoRange()を呼び出す。
            if(KAKKO[i] == -1):
                checkKakkoRange(i, command_string)
            
            if(MEMORY[POINTER] == 0):
                ## ちゃんと対応する']'があるか?
                if(KAKKO[KAKKO[i]] == i):
                    i = KAKKO[i] + 1
                    continue
                else:
                    print("エラー:\'[\'\']\' の数が一致しません。")
                    return
        elif(char == "]"):
            ## ']'の場合、checkKakkoRange()は呼び出し不要。(対応する'['の時点で呼び出されてるはずなので)
            if(MEMORY[POINTER] != 0):
                if(KAKKO[KAKKO[i]] == i):
                    i = KAKKO[i] + 1
                    continue
                else:
                    print("エラー:\'[\'\']\' の数が一致しません。")
                    return


ソース全体

import sys
sys.path.append("C:\\Program Files\\Anaconda3\\Lib\\site-packages\\")

import openpyxl as pyxl
from openpyxl import load_workbook

#print(pyxl.__file__)

MEMORY = []
KAKKO = []
POINTER = 0
MEMORY_LENGTH = 30
RESULT_STRING=""

WORK_BOOK = load_workbook('brainf_ck.xlsx')
WORK_SHEET = WORK_BOOK.get_sheet_by_name('Sheet1')

def init():
    for i in range(MEMORY_LENGTH):

        global POINTER

        POINTER = i
        MEMORY.append(0)
        ##ワークシートに書き出し
        writeMemoryToSheet(MEMORY[i])

    POINTER = 0

def interpreter():

    global RESULT_STRING
    global POINTER
    command_string = str(WORK_SHEET['B1'].value)

    if(command_string.count('[') != command_string.count(']')):
        print("エラー:\'[\'\']\' の数が一致しません。")
        return

    for j in range(len(command_string)):
        KAKKO.append(-1)

    i = 0
    if(command_string[0] == "'"):
        i = 1

    while i < len(command_string):

        char = command_string[i]

        if(char == ">"):
            POINTER += 1
            if(POINTER >= MEMORY_LENGTH):
                print("エラー:不正な\'>\'があります。")
                return
        elif (char == "<"):
            POINTER -= 1
            if(POINTER < 0):
                print("エラー:不正な\'<\'があります。")
                return
        elif(char == "+"):
            MEMORY[POINTER] += 1
            writeMemoryToSheet(MEMORY[POINTER])
        elif(char == "-"):
            MEMORY[POINTER] -=1
            writeMemoryToSheet(MEMORY[POINTER])
        elif(char == "."):
            RESULT_STRING += chr(MEMORY[POINTER])
        elif(char == "["):
            if(KAKKO[i] == -1):
                checkKakkoRange(i, command_string)

            if(MEMORY[POINTER] == 0):
                if(KAKKO[KAKKO[i]] == i):
                    i = KAKKO[i] + 1
                    continue
                else:
                    print("エラー:\'[\'\']\' の数が一致しません。")
                    return
        elif(char == "]"):
            if(MEMORY[POINTER] != 0):
                if(KAKKO[KAKKO[i]] == i):
                    i = KAKKO[i] + 1
                    continue
                else:
                    print("エラー:\'[\'\']\' の数が一致しません。")
                    return
        elif(char == ","):
            while True:
                input_char = input("半角英数1文字を入力してください。")
                if(len(input_char) != 1):
                    print("エラー:1文字ではありません。")
                else:
                    char_code = ord(input_char)

                    if(char_code < 0 or 127 < char_code):
                        print("エラー:半角文字ではありません。")
                    else:
                        MEMORY[POINTER] = char_code
                        writeMemoryToSheet(MEMORY[POINTER])
                        break
        i += 1

def checkKakkoRange(idx, target_string):

    for i in range(idx + 1, len(target_string)):

        kakko_count = 0
        check_char = target_string[i]

        if(check_char == "["):
            kakko_count += 1
        elif(check_char == "]"):

            if(kakko_count == 0):
                KAKKO[idx] = i
                KAKKO[i] = idx
                break
            else:
                kakko_count -= 1


def writeMemoryToSheet(value):

    #global POINTER
    memory_string_length = len("000" + str(value))
    memory_string = ("000" + str(value))[memory_string_length -3:]

    row = 0
    col = (POINTER % 10) + 2

    if(POINTER <= 9):
        row = 4
    elif(POINTER >= 10 and POINTER <= 19):
        row = 5
    else:
        row = 6

    WORK_SHEET.cell(row=row, column=col).value = memory_string

##ここからメイン処理
init()
interpreter()

WORK_BOOK.save('brainf_ck.xlsx')

print("文字列:" + RESULT_STRING)
print("\n" + "終了")


ちなみに、実際に実行させてみた動画がこちら。

いや、やはりどんなものであれ、まずは1個何か作ってみると、(Pythonに限らず)その言語の理解がより深まりますね。

てかbrainf*ck、「難解言語」とか「ク*言語」とか言われるけど、文字列、メモリ、ポインタの考え方とか、むしろ初学者とかの教育にはかなり向いてるんじゃないの?とか思ったり...

ただ、もっとポインタやメモリの動きがリアルタイムに分かるといいなあ...
(本当はExcelを表示させながらやる予定だったが、起動してたら書き込み時にエラーになるので、断念...

てか、当然といえば当然ですよね...)

【python】pythonでExcelを操作する

去年、python関連の書籍を探してたら、こんな本があった。

退屈なことはPythonにやらせよう

pythonといえば、AIや機械学習...と思っていたけど、それ以外にもルーティンワーク系処理の自動化にもなかなか便利。

で、今回はこの本にもある「Excel操作」について、ちょこっと触れてみた。
(ExcelPythonにも対応するらしいし。)

ブックを開く&シートの値取得

import openpyxl as pyxl
from openpyxl import load_workbook

## 既存のブックを開く場合
work_book = load_workbook('test.xlsx')
work_sheet = work_book.get_sheet_by_name('Sheet1')

## 新規WorkBookを作成する場合
new_workbook = pyxl.Workbook()

## 新規シートを作成して取得。
## もちろんシート名指定以外にも、やり方はある。(あくまで一例)
new_workbook.create_sheet('New_Sheet', 0)
new_sheet = new_workbook.get_sheet_by_name('New_Sheet')

## 値をCell形式で取得する方法
target_cell = work_sheet.cell(row=1, column=1)
    
## Range形式で取得する方法
target_range = work_sheet['A1']

## 複数範囲で取得する方法。
## coordinameはアドレスを取得できる。
for rows in work_sheet['A1':'C3']:
    for col in rows:
        print(col.coordinate, col.value)


シートの値設定&ファイルの保存

## 値&数式の設定(Cells形式&Range形式)
new_sheet.cell(row=1, column=3).value = 'abc'
new_sheet["B2"] = "SUM(A3:C3)"

## シートを保存(物理ファイルとして)
new_workbook.save('test2.xlsx')


まだまだ本当に基本的なところしか網羅できてないけど、もっといろいろ知識を増やしていきたいなあ。

てか、Excelpythonが使用できれば、ソースファイルの共有とか、いろいろ可能性が出てくるので、今後に期待したいところです。