20201113のC#に関する記事は2件です。

C#でjsonを読み込み・そして辞書型に変換(強引)

お久しぶりです。

Qiitaの皆さん、お久しぶりです。
前回からかなり時間が空きすぎましたが、あれから念願の新しいパソコンを購入しました。
そしてPythonにも飽きてきたので、C#に手を出してみることにしました。

理解するメモとして書き残しておきます。
ガバな点はご容赦ください。

ふと思ったjsonの読み込みについて

私は以前、Pythonでjsonを使用して設定ファイルやデータをイチイチに定義しなければならないものをjsonに格納して便利に使っていたので、ぜひC#でも使いたいと思い模索しました。
薄々気づいてはいましたが、Pythonはなんて素晴らしいライブラリを取り揃えているのかと思い知らされることになりました。

json読み込みのコード

hoge.json
{
  "hoge": "hoge1",
  "hogehoge": "hoge2",
  "hogehogehoge": "hoge3"
}

Pythonでのjsonの読み込みはjsonライブラリを使用しますが

import json

def load_json(filename):
    with open(filename) as files:
        load = json.load(files)

    return load

このように関数を一つ定義してしまえば、辞書型で帰ってくるので

result = load_json("hoge.json")

hoge1 = result["hoge"]
hoge2 = result["hogehoge"]
hoge3 = result["hogehogehoge"]

print(hoge1)
print(hoge2)
print(hoge3)

print(type(hoge1))
print(type(hoge2))
print(type(hoge3))

hoge1
hoge2
hoge3
<class 'str'>
<class 'str'>
<class 'str'>

こうすると簡単にstrやintで帰ってきますので、あとは煮るなり焼くなりすれば簡単に使うことができますが
(ガバコードデゴメンネ)

C#の場合

using System;
using System.IO;
using System.Text;
using System.Text.Json;

namespace ConsoleApp2
{
    class Program
    {
        public static string ReadAllLine(string filePath, string encodingName)
        {
            StreamReader sr = new StreamReader(filePath, Encoding.GetEncoding(encodingName));
            string allLine = sr.ReadToEnd();
            sr.Close();

            return allLine;
        }

        class hogejson
        {
            public string hoge { get; set; }
            public string hogehoge { get; set; }
            public string hogehogehoge { get; set; }
        }
        static void Main(string[] args)
        {
            string readjson = ReadAllLine("hoge.json", "utf-8");

            hogejson jsonData = JsonSerializer.Deserialize<hogejson>(readjson);

            string hoge = jsonData.hoge;
            string hogehoge = jsonData.hogehoge;
            string hogehogehoge = jsonData.hogehogehoge;

            Console.WriteLine(hoge);
            Console.WriteLine(hogehoge);
            Console.WriteLine(hogehogehoge);

            Console.WriteLine(hoge.GetType());
            Console.WriteLine(hogehoge.GetType());
            Console.WriteLine(hogehogehoge.GetType());

        }
    }
}
hoge1
hoge2
hoge3
System.String
System.String
System.String

こんな感じで記載しないとうまく読み込まないのですが、一番個人的に面倒なのが
「jsonのクラスを作らないといけない」
のと
「メソッド(Pythonでいう関数(若干違うけど))作った時わかりにくい!
ことが引っかかりました。

なぜこんなことになってしまったのか

Pythonは先程の関数で帰ってくる返り値は辞書型に対してC#は特定の返り値を指定しなければなりません。
このため、Pythonでは辞書型で帰ってくるので

hoge = result["hoge"]

とresultに指定定するだけでkeyである「hoge」のvalue「hoge1」を取り出すことができますが
対してC#は、例えば「hoge.json」のkeyである「hoge」のvalueが「hoge1」であったとき、クラス「hogejson」のhogeにstring型(str)でセットされます。
逆にこれをint型や別の型でセットしようとしてもできません。

なぜなら、クラスhogeの返り値はstringと決めているからです。
そのためPythonでよくお世話になった辞書型に返り値には指定されていないため、仮に返り値を"勝手"に辞書型に指定しても他の「hogehoge」や「hogehogehoge」のkeyはおろかvalueの情報すらありません(自己解釈)

ほんじゃあ辞書型に返ってくるように作ろう!笑

探してみたところ、C#には「Dictionaryクラス」というものが存在するようで、それでPythonの辞書型と同じように使えるみたいです。

なら話は早いです、hoge.jsonのkeyとvalueを辞書型に詰め込めるよう試行錯誤を繰り返してできたのがこちらです。

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;

namespace ConsoleApp2
{
    class library
    {
        // ファイル読み込み
        public string ReadAllLine(string filePath, string encodingName)
        {
            StreamReader sr = new StreamReader(filePath, Encoding.GetEncoding(encodingName));
            string allLine = sr.ReadToEnd();
            sr.Close();

            return allLine;
        }

        // List型をDictionary型に強引に変換する
        public static Dictionary<string, string> ListInDictionary(string[] left, string[] right)
        {

            // 一致したとき
            if (left.Length == right.Length)
            {

                var result = new Dictionary<string, string>();

                // leftのListの数の分だけforを回す
                for (int i = 0; i < left.Length; i++)
                {

                    // resultに辞書を追加
                    result.Add(left[i], right[i]);
                }

                return result;

            }

            // 不一致のとき
            else
            {
                return null;
            }
        }

        class hogejson
        {
            public string hoge { get; set; }
            public string hogehoge { get; set; }
            public string hogehogehoge { get; set; }
        }
        //hoge.jsonを読み込むためのメソッド
        public Dictionary<string, string> GetHogejson(string filename)
        {
            try
            {
                string jsonfile = ReadAllLine(filename, "utf-8");

                hogejson jsonData = JsonSerializer.Deserialize<hogejson>(jsonfile);

                string[] json_key = { "hoge", "hogehoge", "hogehogehoge" };
                string[] json_value = { jsonData.hoge, jsonData.hogehoge, jsonData.hogehogehoge };

                var result = ListInDictionary(json_key, json_value);

                return result;
            }

            // jsonが読み込めない時
            catch (JsonException)
            {
                return null;
            }

        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            library Library = new library();

            Dictionary<string, string> gethogejson = Library.GetHogejson("hoge.json");

            string hoge, hogehoge, hogehogehoge;

            hoge = gethogejson["hoge"];
            hogehoge = gethogejson["hogehoge"];
            hogehogehoge = gethogejson["hogehogehoge"];

            Console.WriteLine(hoge);
            Console.WriteLine(hogehoge);
            Console.WriteLine(hogehogehoge);

            Console.WriteLine(hoge.GetType());
            Console.WriteLine(hogehoge.GetType());
            Console.WriteLine(hogehogehoge.GetType());

        }
    }
}

...自分でも感じた、強引すぎると...

問題点

  1. valueがint型だろうとなんだろうとstring型にしてresult(辞書型)に格納する。
  2. 結局jsonデータのクラスを指定しなければならないので、根本的な解決には至っていない。
  3. とりあえず思いついた発想と知恵で強引に作ったので、見られたら怒られるくらいのガバコード

個人的にはPythonのように使えるのが一番ありがたいですが、あまりに強引すぎて怒られるような気がします。

ちなみに結果は

hoge1
hoge2
hoge3
System.String
System.String
System.String

こんなふうに表示されます。

最後に

この方法より「こうしたほうがいいよ~・ガバすぎこれを使え」等あれば、ご遠慮無くぜひコメントまで!
結構真剣に困っていたので、また時間があれば改良してみます。

追記
これなんなんですかね?よく出てきて動かなくなります。
こうなるともう保存して起動し直すしかないのでめっちゃ不便です。Screenshot_11.png

久々に書き切りました。
おやすみなさい。

引用元

https://usefuledge.com/csharp-json.html
https://json2csharp.com/ (先程のjsonデータクラスをjsonデータをもとに作ってくれるサイト、めっちゃ便利)
Thank you!!!!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

C# Wordで脚注と文末脚注を挿入

Wordで記事を執筆する時、ある文章の内容について、補足説明する必要があるなら、脚注機能を使うことがあります。例えば、

f:id:lendoris:20201111113925p:plain


こういうふうに使いますね。レポートや論文でたくさん使っている機能だから、皆さんもう慣れていらっしゃるでしょう?今回はWordで脚注と文末脚注を挿入する方法を紹介します。

閑話休題、本題に入りましょう!

下準備

1.E-iceblueの公式サイトからFree Spire.Doc for .NET無料版をダウンロードしてください。

f:id:lendoris:20201027114413p:plain



2.Visual Studioを起動して新規プロジェクトを作成してから、インストールされたファイルにあった相応しいDoc.dllを参照に追加してください。

Net 4.0を例としたら、デフォルトパスは“Bin→NET4.0→Spire.Doc.dll”というようです。)

 

f:id:lendoris:20200922164301p:plain

元のファイル

 

f:id:lendoris:20201111113930p:plain

サンプルコード

using Spire.Doc;
using Spire.Doc.Documents;
using Spire.Doc.Fields;
using System.Drawing;

namespace ConsoleApplication24
{
    class Program
    {
        static void Main(string[] args)
        {
            // Word objectを作成し、ドキュメントをロードします。
            Document document = new Document();
            document.LoadFromFile(@"テキスト.docx", FileFormat.Docx2010);

            //初めの段落を取得します。
            Paragraph paragraph = document.Sections[0].Paragraphs[0];

            //脚注を追加します。
            Footnote footnote = paragraph.AppendFootnote(FootnoteType.Footnote);

            //初めの段落で"夏時間"という文字列を探し、脚注に追加します。
            DocumentObject obj = null;

            for (int i = 0; i < paragraph.ChildObjects.Count; i++)
            {
                obj = paragraph.ChildObjects[i];
                if (obj.DocumentObjectType == DocumentObjectType.TextRange)
                {
                    TextRange textRange = obj as TextRange;

                    if (textRange.Text == "夏時間")
                    {
                        // String文字列の書式を設定します。
                        textRange.CharacterFormat.Bold = true;
                        //脚注を挿入します。
                        paragraph.ChildObjects.Insert(i + 1, footnote);
                        break;
                    }
                }
            }

            //脚注の内容を追加し、文字のフォントなどを設定します。
            TextRange text = footnote.TextBody.AddParagraph().AppendText("夏時間。カナダ、オーストラリアでも用いる)とは1年のうち夏を中心とする時期に太陽が出ている時間帯を有効に利用する目的で、標準時を1時間進める制度またはその進められた時刻のこと。ただし、オーストラリアのロード・ハウ島では夏時間と通常の時間の差が30分であるなど一律ではない。");
            text.CharacterFormat.FontName = "Arial Black";
            text.CharacterFormat.FontSize = 10;
            text.CharacterFormat.TextColor = Color.DarkGray;
            footnote.MarkerCharacterFormat.FontName = "Calibri";
            footnote.MarkerCharacterFormat.FontSize = 12;
            footnote.MarkerCharacterFormat.Bold = true;
            footnote.MarkerCharacterFormat.TextColor = Color.DarkGreen;


            //三つ目の段落を取得します。
            Paragraph paragraph2 = document.Sections[0].Paragraphs[2];

            //文末脚注を挿入し、スタイルを設定します。
            Footnote endnote = paragraph2.AppendFootnote(FootnoteType.Endnote);

            TextRange text2 = endnote.TextBody.AddParagraph().AppendText("出典元:Wikipedia");
            text2.CharacterFormat.FontName = "Arial Black";
            text2.CharacterFormat.FontSize = 10;
            text2.CharacterFormat.TextColor = Color.DarkGray;
            endnote.MarkerCharacterFormat.FontName = "Calibri";
            endnote.MarkerCharacterFormat.FontSize = 12;
            endnote.MarkerCharacterFormat.Bold = true;
            endnote.MarkerCharacterFormat.TextColor = Color.DarkGreen;

            //保存します。
            document.SaveToFile("脚注.docx", FileFormat.Docx2010);
        }
    }
}

 できました!

 

f:id:lendoris:20201111113938p:plain

 

 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む