20
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

文字列を任意の固定長で切り分けてみる

Last updated at Posted at 2017-10-04

目的

えとー、base64の文字列に改行を入れたかったんです。
VSで開発するC#の話です。

まぁInsertLineBreaksを指定すれば、76文字毎に改行コードを入れてくれる事は知ってますけど。
でも、どーしても80文字で改行したいんだよー

まずは力技

string text = "aaaabbbbccccddddeeee";

const int SIZE = 7;
text += new string(' ', (SIZE - text.Length % SIZE) % SIZE);
string[] lines = new string[text.Length / SIZE];
for(int i = 0; i < lines.Length; i++)
	lines[i] = text.Substring(i * SIZE, SIZE).TrimEnd();

foreach(string s in lines)
	Console.WriteLine("'{0}'", s);

結果はこんな感じで、無問題。

image

力技ではあるが、予め入力文字列の長さを調整してあるので、切り分けは若干シンプルになっております。

んー
でもなぁ、イマイチ美しくないんだよねー

正規表現って使えないのかなぁ?

お次はやっぱり正規表現。
真っ先に思いつくのはMatchesですね。
でもMatchCollectionを受けて、foreachでくるくる回るんじゃ力技と大して変わらない。ここはやっぱりLinqでしょ。
えー、グーグル先生は物知りなんでー

ほらやっぱりあった

string text = "aaaabbbbccccddddeeee";

foreach(string s in Regex.Matches(text, @".{1,7}")
                                .Cast<Match>()
                                .Select(m => m.Value)
                                .ToArray())
	Console.WriteLine("'{0}'", s);

こんな感じだー
中々綺麗に纏まりました。

※結果は前と同じなので省略で~す

でも何かコスト高そうだなぁ…

もう一歩踏み込む

そんなこんなで、正規表現確認してたらSplitってメソッドがあるじゃん。これならstring[]で返してくれるのでMatchesよりも良さげ。

んーんん…
でもさ、そんな都合の良い区切り文字なんて無いよー


と云い乍も思い出した。
えーと確かここら辺に(ごそごそっ、と)…
あー、あったあった、これだよ

何も具体的な文字である必要はない。アンカーで充分って事だよね。


取り敢えずは「肯定的後読み」かな?

(?<=.{80})

とかでどうだろ?
任意の文字80桁の後ろにマッチする訳で…

image

あれ?ダメだ。
うーーーんと、そっか
一文字ずつ進んでいくから一旦マッチすると、それ以降は一文字ずつマッチしてしまうんだ。

もう一回msdnをじっくり見てみましょうか。
あ、見っけ。

\Gアンカーだ。前回一致した位置にマッチするからこれを組み合わせれば、必ず指定文字幅毎に一致する筈だ。

(?<=\G.{80})

ばっちり!

と思ったら、問題が一つ。

screen.png

文字列長が丁度分割文字幅の倍数である時には最後に空文字が出てしまう…
まぁ、そうだよなぁ…
滅多にある事では無し、これで良しとするかなぁ…



いや、ダメだ!
諦めるんじゃないっ
あらびき日記を読み返せ

と云う事で、読み返しました。
否定先読み利用して末尾のみをマッチ対象から外してやればいいんじゃね?

と云う事で以下。

string text = "aaaabbbbccccddddeeee";

foreach(string s in Regex.Split(text, @"(?<=\G.{4})(?!$)"))
	Console.WriteLine("'{0}'", s);

image

素晴らしい

おっといけねー

本来の目的を忘れておるぞ。
分割した文字列を配列で欲しければ此処までの話で良いんだが、改行コードで区切りたい時はどうするか。入手した配列をJoinでくっつけても良いけど、配列にしてから改めてくっつけると云うのが如何にも遠回り。

此処までくればReplaceメソッド使って、アンカーを改行コードに置き換えれば良い、と云う事に自然と気が付く。

string text = "aaaabbbbccccddddeeee";

Console.WriteLine(Regex.Replace(text, @"(?<=\G.{4})(?!$)", Environment.NewLine));

image

すんげーぞ
めちゃ簡潔になった…


しかし、結果的にお馴染みReplaceメソッドに落ち着いたけど、Splitに気が付いたからこそ、此処に辿り着いた気がする。最初っからすんなり気が付ける様に精進しなくては、と思いました。

20
17
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?