ブログ「サイバー少年」

ブログ「サイバー少年」へようこそ!
小学六年生ごろからプログラミングを趣味にしている高校生のブログです。
勉強したことについての記事などを書いています。フリーソフトも制作、公開しています。
(当ブログについて詳しくは「ブログ概要紹介」を参照)

サイバー少年が作ったフリーソフトは「サイバー少年の作品展示場」へ

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

tag:

C#でscanf的なことをする

既出ですが、C#でscanf的に値を読み込む方法を書いていきたいと思います。

今回はわりと小さい記事です。
久しぶりにC#カテゴリの記事を書きますが、VB.NETでもPowerShellでも、.NETで動くもので共通ですけどね。


そもそもC言語ではscanf関数を使って

int a,b;
scanf("a:%d, b:%d", &a, &b);


みたいにフォーマットされた文字列を読み込んで指定の部分を変数に格納することができます。


しかし、C#ではこういう関数がないので、どうしようかと困ってしまいますね。

単純なカンマ区切りとかだったらString.Splitで特定の場所を取ったりできますが、なんか自然じゃないし、そもそももっと複雑なフォーマットになるとコードも複雑になります。



じゃあどうするかというと、正規表現のキャプチャを使います。
番号でグループにアクセスしてもいいんですが、わかりやすさのため(?<a>[0-9]+)みたいにグループに名前をつけておきます。

string input = Console.ReadLine();
Match m = Regex.Match(input, "^a:(?<a>[0-9]+), b:(?<b>[0-9]+)$");
int a = int.Parse(m.Groups["a"]);
int b = int.Parse(m.Groups["b"]);


(?<a>[0-9]+)などがscanfでいう%dに相当します。


読み込むのが整数じゃなくて小数だった場合は、scanfでは%fと書けば済みますが、
こちらの正規表現では小数のフォーマットを自前で書かないといけないので多少面倒さは残ります。

あと、負数に対応させる場合も自前で書かないといけないですね。


string input = Console.ReadLine();
Match m = Regex.Match(input, @"^a:(?<a>[0-9]+(\.[0-9]+)?), b:(?<b>-?[0-9]+)$");
float a = float.Parse(m.Groups["a"]);
int b = int.Parse(m.Groups["b"]);



しかし書式を自前で書かないといけないということは、それだけ細かいところに手が届くので、カスタマイズしやすいということでもありますね。

さっき調べてみたら、scanfの書式指定もわりと多機能そうだったんですが、正規表現には敵わないでしょうね。

正規表現では繰り返しの表現が可能ですので、頑張れば任意の長さのカンマ区切りのデータなども読めます。


ということで、正規表現で入力を読み込めば便利という記事でした。

読み込む部分を関数に切り分けて、なんちゃってscanf関数を作ってもいいかもしれないですね。

スポンサーサイト

tag: プログラミング C# C言語 文字列 正規表現 パターンマッチ 入力

後方参照とか.NETの正規表現考察

一週間程前に正規表現についての記事「正規表現の“否定”について勘違いと、アンカー」を書いたばっかりですが、
その記事の最後で、グループとかキャプチャとか後方参照とかをまだ分かっていないという課題を挙げました。

というわけで、それについて調べたので、記事にします。


先にグループとかキャプチャとかが何なのかを書こうと思うのですが、これらは正規表現におけるひとかたまりの単位のことです。

まず、グループというのは正規表現のパターン文字列でグループ化の記号()を用いてグループ化された部分のこと、すなわちこれは正規表現の構文としての一つの単位だと認識しています。

たとえば"I am the (king|queen)"というパターン文字列において、まず括弧で囲まれた"(king|queen)"というグループがひとつあります。

ただし、括弧で囲まれていませんが、パターン文字列全体はひとつのグループとするという決まりがあるようで、このパターン文字列には2つのグループがあることになります。


このように、本当はグループというのは木構造になっているのですが、グループを木構造として扱わずに平坦に扱うのが普通のようです。

実装によりけりかもしれませんが、ほとんどがグループを平坦に扱っていると思います。

これは、グループを平坦に扱うと、パターン文字列内のすべてのグループに一次元的な番号を割り振ることができて、後述する後方参照という仕組みを簡単に利用できるようになるためだと思います。


グループにはそれぞれ番号が割り振られます。

どのように割り振られるかというと、これも実装によりけりかもしれませんが、普通は幅優先探索の順番だと思います。

続きを読む

tag: 正規表現 パターンマッチ 文字列処理 後方参照 .NET

正規表現の“否定”について勘違いと、アンカー

昔、正規表現の基本を学んで、もう基礎的なことは大丈夫だろうと思っていたんですが、思いがけない重大な勘違いをしていました。

“ある文字列でない文字列”の表現の方法なんですが、正規表現ではこの表現が非常にやりづらいみたいで、私のように躓いている人もいると思うのでメモします。

どういうときにこういう正規表現を書くのかというと、私はHTMLのタグ認識をさせていました。

たとえば、以下はXMLですが、

<Root>
<Element>
なまむぎなまごめなまたまご
</Element>
</Root>


このXMLから、Elementの要素、なまむぎなまごめなまたまごを抜き出すための正規表現みたいなのを書こうとしたわけです。

まず、文字列"<Element>"の直後のアンカーを表す"(?<=<Element>)"を書きます。

アンカーも、実は今までよくわかっていなかったので、これも後でメモします。

そして、Elementの要素はなんでもいいので".*"とします。

そして、".*"だけだと"</Root>"までマッチしてしまうので、"</Element">の直前が最後なのだということを表すため、そのアンカーを表す"(?=</Element>"を書きます。

というわけでパターン文字列は"(?<=<Element>).*(?=</Element>)"となります。


ちなみに、".*"の解釈は行末で終わってしまうというのがデフォルトなので、解析対象に改行があった場合は行の概念を無視するように設定しておきます。
続きを読む

tag: 正規表現 パターンマッチ 文字列処理 XML HTML アンカー

当ブログをご利用(閲覧等)になる場合は必ず「当ブログの利用規定」をお守りください。

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。