예제 #1
0
        /// <summary>
        /// BoMatch()呼び出し/結果処理簡略化
        /// </summary>
        /// <param name="pattern">検索パターン(NULLを指定すると、前回のコンパイル済みパターンを使用する)</param>
        /// <param name="options">オプション</param>
        /// <param name="input">検索対象文字列</param>
        /// <param name="targetstart">検索開始文字位置</param>
        /// <param name="targetend">検索終了文字位置</param>
        /// <param name="one_shot">ワンショットモード:通常はfalseを指定</param>
        /// <returns>検索によって見つかった Matched オブジェクト</returns>
        protected Matched BoMatch(
            string pattern,
            string options,
            string input,
            int targetstart,
            int targetend,
            bool one_shot)
        {
            if (this.disposed)
            {
                throw new ObjectDisposedException("BregonigRegexオブジェクト");
            }

            lock (this.pattern)
            {
                // 検索位置をポインタに変換
                AllocText(input);
                IntPtr targetstartp = IntPtr.Add(strstartp, targetstart * sizeof(char));
                IntPtr targetendp   = IntPtr.Add(strstartp, targetend * sizeof(char));

                StringBuilder msgSb = new StringBuilder(80); // エラーメッセージ格納用領域を確保
                int           ret   = BoMatch(pattern, options, strstartp, targetstartp, targetendp, one_shot, ref rxp, msgSb);
                if (ret < 0)
                {   // エラーあり
                    throw new ArgumentException(msgSb.ToString());
                }
                if (ret > 0)
                {
                    // マッチあり:構造体ポインタの最新の内容を取り出し
                    BREGEXP rx          = (BREGEXP)(Marshal.PtrToStructure(rxp, typeof(BREGEXP)));
                    int     arrayLength = rx.nparens + 1; // グループ数+[0]マッチ箇所全体 の分
                    Group[] groups      = new Group[arrayLength];
                    for (int i = 0; i < arrayLength; i++)
                    {
                        groups[i] = rx.CreateGroup(i, this);
                    }
                    return(new Matched(groups, this, targetstart, targetend));
                }
                else
                {
                    return(null);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// BoSubst()呼び出し/結果処理簡略化
        /// </summary>
        /// <param name="subst">置換パターン(NULLを指定すると、前回のコンパイル済みパターンを使用する)</param>
        /// <param name="options">オプション</param>
        /// <param name="input">検索対象文字列</param>
        /// <param name="targetstart">検索開始文字位置</param>
        /// <param name="targetend">検索終了文字位置</param>
        /// <param name="match">置換対象となるMatchedオブジェクト</param>
        /// <returns>置換結果文字列(matchが指定されている場合はマッチした部分の変更結果、matchがnullの場合はinput全体の置換結果)</returns>
        protected string BoSubst(
            string subst,
            string options,
            string input,
            int targetstart,
            int targetend,
            Matched match = null)
        {
            if (this.disposed)
            {
                throw new ObjectDisposedException("BregonigRegexオブジェクト");
            }
            // 置換オプション/置換パターンが前回と一緒であればコンパイルを省略する
            string pattern = this.pattern;

            if (options == this.prevoptions)
            {
                pattern = null;
                options = null;
                if (subst == this.prevsubst)
                {
                    subst = null;
                }
                else
                {   // subst相違あり、今回指定されたsubstを保存
                    this.prevsubst = subst;
                }
            }
            else
            {   // option相違あり、今回指定されたoptionsとsubstを保存
                this.prevoptions = options;
                this.prevsubst   = subst;
            }

            lock (this.pattern)
            {
                // 検索位置をポインタに変換
                AllocText(input);
                IntPtr targetstartp = IntPtr.Add(strstartp, targetstart * sizeof(char));
                IntPtr targetendp   = IntPtr.Add(strstartp, targetend * sizeof(char));

                StringBuilder msgSb = new StringBuilder(80); // エラーメッセージ格納用領域を確保
                int           ret   = BoSubst(pattern, subst, options, strstartp, targetstartp, targetendp, null, ref rxp, msgSb);
                if (ret < 0)
                {
                    // エラーあり
                    throw new ArgumentException(msgSb.ToString());
                }
                if (ret > 0)
                {
                    // 置換成功:構造体ポインタの最新の内容を取り出し
                    BREGEXP rx = (BREGEXP)(Marshal.PtrToStructure(rxp, typeof(BREGEXP)));
                    if (match != null)
                    {
                        Group replacedMatch = rx.CreateGroup(0, this); // 置換された部分のマッチ情報を取得
                        if (match.Index != replacedMatch.Index || match.Length != replacedMatch.Length)
                        {
                            // 検索時/置換時でマッチ箇所が同一にならなかった(通常発生しない。発生したらBregonigRegexのバグ、要究明)
                            throw new SystemException("置換対象のマッチ箇所(Index=" + match.Index + ", Match=" + match.Length + ")"
                                                      + "とは異なる箇所(Index=" + replacedMatch.Index + ", Match=" + replacedMatch.Length + ")が置換されました。");
                        }
                        if (rx.outp == null)
                        {
                            return(string.Empty); // 置換結果が空文字となった
                        }
                        // 置換部分の開始位置=置換結果全体の開始位置+(マッチ箇所の開始位置、ただし探索開始位置考慮)
                        IntPtr replacedstart = IntPtr.Add(rx.outp, (match.Index - targetstart) * sizeof(char));
                        // 置換部分の置換後文字列長=マッチ箇所の置換前文字列長+置換結果全体の文字列長-置換前文字列全体の文字列長
                        int len = match.Length
                                  + (int)((rx.outendp.ToInt64() - rx.outp.ToInt64()) / sizeof(char))
                                  - (targetend - targetstart);
                        // 置換部分の文字列内容のみをピンポイントで抜き出す
                        return(Marshal.PtrToStringUni(replacedstart, len));
                    }
                    else
                    {
                        // 置換後文字列全体を組み立て
                        StringBuilder sb = new StringBuilder();
                        if (targetstart > 0)
                        {
                            sb.Append(input.Substring(0, targetstart));
                        }
                        if (rx.outp != null)
                        {   // 空文字列に置換されていなければ、置換結果の文字列を取り出し
                            int len = (int)((rx.outendp.ToInt64() - rx.outp.ToInt64()) / sizeof(char));
                            sb.Append(Marshal.PtrToStringUni(rx.outp, len));
                        }
                        if (targetend < input.Length)
                        {
                            sb.Append(input.Substring(targetend));
                        }
                        return(sb.ToString());
                    }
                }
                else
                {
                    // 置換箇所なし
                    if (match != null)
                    {
                        // 検索時/置換時でマッチ箇所が同一にならなかった(通常発生しない。発生したらBregonigRegexのバグ、要究明)
                        throw new SystemException("置換対象のマッチ箇所(Index=" + match.Index + ", Match=" + match.Length + ")が検出できませんでした。");
                    }
                    // 置換前テキスト内容のまま変更なし
                    return(input);
                }
            }
        }