2ちゃんねるの DAT を読む


自作のフレームワークを用いて2ちゃんねるの DAT リーダーでも作ってみようかと思ったのです。

public class DatLine
{
	[RecordField(0)]
	public string Name { get; set; }

	[RecordField(1)]
	public string Email { get; set; }

	[RecordField(2, ParserType = typeof(DateTimeParser))]
	public DateTime DateTime { get; set; }

	[RecordField(2, ParserType = typeof(IDParser))]
	public string ID { get; set; }

	[RecordField(3, ParserType = typeof(TextParser))]
	public string Text { get; set; }

	[RecordField(4, NullString = "")]
	public string ThreadName { get; set; }
}
class DateTimeParser : IParser
{
	private static readonly Regex DateTimeRegex = new Regex(@"\b(?<datetime>\d+/\d+/\d+ \d+:\d+:\d+(\.\d+)?)\b", RegexOptions.Compiled);

	public object Parse(string value)
	{
		Match match = DateTimeRegex.Match(value);
		return DateTime.Parse(match.Groups["datetime"].Value);
	}
}
class IDParser : IParser
{
	private static readonly Regex IDRegex = new Regex(@"\bID:(?<id>.+)\b", RegexOptions.Compiled);

	public object Parse(string value)
	{
		Match match = IDRegex.Match(value);
		return match.Success ? match.Groups["id"].Value : null;
	}
}
class TextParser : IParser
{
	private static readonly Regex HtmlTagRegex = new Regex(@"<[^<>]+>", RegexOptions.Compiled | RegexOptions.Singleline);
	private static readonly string[] Separator = new string[] { "<br>" };

	// 扱いやすいように平文に戻しておく。
	public object Parse(string value)
	{
		var lines = from line in value.Split(Separator, StringSplitOptions.None)
		            select HttpUtility.HtmlDecode(line.Trim());
		string text = string.Join(Environment.NewLine, lines.ToArray());
		return HtmlTagRegex.Replace(text, "");
	}
}

で,こんな感じに使います。

var settings = new CsvReaderSettings()
{
	Encoding = Encoding.GetEncoding("shift_jis"),
	Separator = "<>",
	Delimiter = Delimiter.Unix,
};

using (var stream = File.OpenRead(datPath))
using (var reader = new CsvReader(stream, settings))
{
	var posts = reader.ReadToEnd<DatLine>().ToList();
}

適当なスレッドから DAT ファイルを持ってきて試してみると例外が投げられます。何がおかしいのか見てみると, 1001 番目のレス,すなわちスレ終了のレスの日時や ID が記述されている列に "Over 1000 Thread" とあります。どうやら DAT の仕様としては,日付・ ID 欄にスレッド終了や削除の情報が書かれている模様です。

要は DateTime が存在しないレスがありうるということです。つまり Nullable<DateTime> にしておけばとりあえず読めるようになるわけです。ということで DatLineDateTimeParser を修正。

public DateTime? DateTime { get; set; }
return match.Success ? (DateTime?)DateTime.Parse(match.Groups["datetime"].Value) : null;

とりあえずこれで読めるようにはなりました。サーバーから直接 DAT を取得したい場合はストリームを適当に変えれば良いわけです。大ざっぱにいくつかスレッドを見ただけなので対応していない板とかあるのでしょうが,細かい修正はおいおいやっていけば良いことです。

あとは取得した DAT を RSS に変換するなり自分好みの処理すればよいわけです[A]

脚注

  1. スレッドを RSS に変換してくれるウェブサービスは既に存在します (2ch to RSS)。 []