Help us understand the problem. What is going on with this article?

2文字目以降に大文字が来たらアンダーバーを挿入するプログラムを書いてみた

More than 1 year has passed since last update.

初投稿です。
至らない点がありましたら教えて頂けると幸いです。

概要

受け取った文字に一工夫加えたいなと思って調べてたら、正規表現を使えばいけそうだったので、練習も兼ねてアンダーバーを挿入するプログラムを書いてみました。

実装

やったことは正規表現を使って先頭末尾以外の大文字でパターンマッチした文字列を保存しておいて、その文字列の位置を検索してアンダーバーを挿入するだけです。

実際にやってみた結果こんな感じになりました。
確認環境はUnity2017で試しています。

コード

結果表示にエディタ拡張を使っています。
今回はアンダーバーを挿入するのが目的のため、エディタ拡張部分の説明は割愛します。

public class RegexWindow : EditorWindow
{
    private string _defaultText;

    [MenuItem("Window/RegexWindow")]
    private static void Open()
    {
        var window = GetWindow<RegexWindow>();
    }

    private void OnGUI()
    {
        EditorGUILayout.BeginVertical();
        _defaultText = EditorGUILayout.TextField("通常表示", _defaultText);
        if (!string.IsNullOrEmpty(_defaultText))
        {
            //元データと比べたいためコピーを作る
            string result = string.Copy(_defaultText);
            //検索パターン。今回は先頭末尾以外の大文字を検索する
            var regex = new Regex(@"\B[A-Z]");
            //パターンに一致した文字列を配列で確保
            var matches = regex.Matches(result);

            //先頭文字には挿入させないため1にしておく
            int searchIndex = 1;
            //次の文字列の検索するための増加分
            const int ADD_SEARCH_NUM = 2;
            //挿入したい文字を入れる。今回はアンダーバー
            const string INSERT_TEXT = "_";

            //パターンにマッチした分だけ回す
            foreach (var match in matches)
            {
                //文字列の場所を検索。成功すると0以上の数字が返ってくる
                int findIndex = result.IndexOf(match.ToString(), searchIndex);
                if (findIndex >= 0)
                {
                    result = result.Insert(findIndex, INSERT_TEXT);
                    searchIndex = findIndex + ADD_SEARCH_NUM;
                }
            }
            EditorGUILayout.LabelField("結果", result);
        }
        EditorGUILayout.EndVertical();
    }       
}

解説

ADD_SEARCH_NUMを2にしている理由はアンダーバーを挿入すると検索に使った文字が一つ後ろに下がるのでそれの補正と検索した位置の次の文字を探したいために1つインデックスを増やしています。

上のコードで言うとTestTestでパターンマッチした時に5番目のTが一致して、IndexOfでその位置のインデックスを返しますが、その後にアンダーバーを挿入すると一文字増えます。そのためTが一つ後ろにずれてTのインデックスの位置が6番目になってしまうため増やしています。


TestTest→Test_Test

追記(2018/3/5)

@oigami013さんにIndexOfを使わないで変換する方法を教えてもらったので、そっちのやり方も書いておきます。

public class RegexWindow : EditorWindow
{
    private string _defaultText;

    [MenuItem("Window/RegexWindow")]
    private static void Open()
    {
        var window = GetWindow<RegexWindow>();
    }

    private void OnGUI()
    {
        EditorGUILayout.BeginVertical();
        _defaultText = EditorGUILayout.TextField("通常表示", _defaultText);
        if (!string.IsNullOrEmpty(_defaultText))
        {
            //元データと比べたいためコピーを作る
            string result = string.Copy(_defaultText);
            result = Regex.Replace(result, @"\B[A-Z]", s => "_"+ s.Value);

            EditorGUILayout.LabelField("結果", result);
        }
        EditorGUILayout.EndVertical();
    }       
}

パターンマッチした文字の前に_を追加して置き換えで同じことが出来るとは…。
勉強になりました。教えていただきありがとうございます!

参考

http://gimite.net/help/devas-ja/all_regex.html
https://dobon.net/vb/dotnet/string/stringindexof.html
https://qiita.com/mochizukikotaro/items/84f3ab2740b8efbe0dc6

daria_sieben
主に自分が調べたことを忘備録として書いています
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away