import re
import os
import ctypes
from datetime import datetime, timedelta
from pathlib import Path
def parse_diary_entries(text):
"""日記テキストを日付ごとに分割してパース"""
# 日付パターン
date_pattern = r'-\s+(\w+),\s+(\w+)\s+(\d+),\s+(\d+)\s+(\d+):(\d+)'
# 月名を数字に変換
months = {
'January': 1, 'February': 2, 'March': 3, 'April': 4,
'May': 5, 'June': 6, 'July': 7, 'August': 8,
'September': 9, 'October': 10, 'November': 11, 'December': 12
}
entries = []
# すべての日付位置を見つける
matches = list(re.finditer(date_pattern, text))
for i, match in enumerate(matches):
day_of_week, month, day, year, hour, minute = match.groups()
month_num = months.get(month)
if not month_num:
continue
# 日付オブジェクトを作成
date = datetime(int(year), month_num, int(day), int(hour), int(minute))
# 本文の開始位置(日付行の終わり)
content_start = match.end()
# 本文の終了位置(次の日付の開始、または文末)
if i + 1 < len(matches):
content_end = matches[i + 1].start()
else:
content_end = len(text)
# 本文を抽出
content = text[content_start:content_end].strip()
entries.append({
'date': date,
'day_of_week': day_of_week,
'time': f"{hour}:{minute}",
'content': content
})
return entries
def convert_to_markdown(entry_data):
"""エントリデータをMarkdown形式に変換"""
date_iso = entry_data['date'].strftime('%Y-%m-%d')
# 前日と翌日の日付を計算
prev_date = (entry_data['date'] - timedelta(days=1)).strftime('%Y-%m-%d')
next_date = (entry_data['date'] + timedelta(days=1)).strftime('%Y-%m-%d')
# Markdownファイルの内容を生成
markdown = ""
# 前後の日付へのリンク
markdown += f"[[{prev_date}]] | [[{next_date}]]\n\n"
# 本文の改行を保持(Markdownでは行末に2つのスペースで改行)
content_lines = entry_data['content'].split('\n')
for line in content_lines:
if line.strip():
markdown += line + " \n"
else:
markdown += "\n"
# タグを追加
markdown += "\n#diary\n"
return date_iso, markdown
def set_file_times_windows(filepath, timestamp):
"""Windowsでファイルの作成日時、更新日時、アクセス日時を設定"""
# Windows API の定義
kernel32 = ctypes.windll.kernel32
# 定数
GENERIC_WRITE = 0x40000000
FILE_SHARE_READ = 0x00000001
FILE_SHARE_WRITE = 0x00000002
OPEN_EXISTING = 3
FILE_ATTRIBUTE_NORMAL = 0x80
# ファイルハンドルを開く
handle = kernel32.CreateFileW(
str(filepath),
GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
None,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
None
)
if handle == -1:
print(f"ファイルを開けませんでした: {filepath}")
return
try:
# datetimeをWindowsのFILETIME形式に変換
# FILETIMEは1601年1月1日からの100ナノ秒単位
unix_epoch = datetime(1970, 1, 1)
windows_epoch = datetime(1601, 1, 1)
# Unixエポックからの秒数を取得
delta = timestamp - windows_epoch
# 100ナノ秒単位に変換
filetime = int(delta.total_seconds() * 10000000)
# FILETIME構造体を作成
class FILETIME(ctypes.Structure):
_fields_ = [
("dwLowDateTime", ctypes.c_uint32),
("dwHighDateTime", ctypes.c_uint32)
]
ft = FILETIME()
ft.dwLowDateTime = filetime & 0xFFFFFFFF
ft.dwHighDateTime = filetime >> 32
# ファイル時刻を設定(作成日時、アクセス日時、更新日時)
kernel32.SetFileTime(
handle,
ctypes.byref(ft), # 作成日時
ctypes.byref(ft), # アクセス日時
ctypes.byref(ft) # 更新日時
)
finally:
kernel32.CloseHandle(handle)
def process_diary(input_text, output_dir='diary'):
"""日記テキストを処理してファイルに出力"""
# 出力ディレクトリを作成
Path(output_dir).mkdir(exist_ok=True)
# エントリをパース
entries = parse_diary_entries(input_text)
# 日付順にソート
entries.sort(key=lambda x: x['date'])
for entry_data in entries:
# Markdownに変換
filename, markdown_content = convert_to_markdown(entry_data)
# ファイルに書き出し
output_path = Path(output_dir) / f"{filename}.md"
with open(output_path, 'w', encoding='utf-8') as f:
f.write(markdown_content)
# Windowsでファイルのタイムスタンプを設定
set_file_times_windows(output_path, entry_data['date'])
print(f"作成: {output_path}")
# メイン処理
if __name__ == "__main__":
# diary.txtを読み込み
try:
with open('diary.txt', 'r', encoding='utf-8') as f:
diary_text = f.read()
print("diary.txtを読み込みました")
print("変換を開始します...\n")
# 変換実行
process_diary(diary_text)
print("\n変換が完了しました!")
except FileNotFoundError:
print("エラー: diary.txtが見つかりません")
print("スクリプトと同じディレクトリにdiary.txtを配置してください")
except Exception as e:
print(f"エラーが発生しました: {e}")