001    /*
002     * Copyright (c) 2009 The openGion Project.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013     * either express or implied. See the License for the specific language
014     * governing permissions and limitations under the License.
015     */
016    package org.opengion.fukurou.util;
017    
018    import java.util.Set;
019    import java.util.TreeSet;
020    import java.util.Iterator;
021    
022    /**
023     * ReplaceString.java は、è¤?•°のæ–?­—å?をä¸?‹¬置換するå?合に使用するクラスですã?
024     *
025     * add メソãƒ?ƒ‰でã€?–‹始アドレス、終äº?‚¢ドレス、置換文字å?を指定しã€?
026     * æœ?¾Œに、replaceAll で、変換を行いますã?
027     * 通常、異なる文字å?をä¸?‹¬で変換する場合ã?é€??に変換アドレスを求めてã€?
028     * 後ろからé ?�«置換してã�?�‹なã�?�¨、前から処ç�?�™ると処ç�?�”とにアドレスã�?
029     * 変更になりä¸?�‹らå?計算することになりますã?これは、登録時ã?、どのような
030     * é ?º�でもよくã?replaceAll 時に、å?部に登録æŒ?®šある変換æ–?­—å?の開始アドレスより
031     * 自動的にé€??で置換するためã?è¤?•°の置換å?æ‰?�Œあってもã?まとめて処ç�?�§きますã?
032     * ただしã?è¤?•°の置換å?æ‰?�Œある場合ã?重è¤?¦�ç´?�Œあれば、エラーになりますã?
033     *
034     * @version  4.0
035     * @author       Kazuhiko Hasegawa
036     * @since    JDK5.0,
037     */
038    public final class ReplaceString {
039            private final Set<ReplaceData> set = new TreeSet<ReplaceData>();
040    
041            /**
042             * 開始アドレス、終äº?‚¢ドレス、置換文字å?を指定し置換対象を追åŠ?�—ますã?
043             * 通常、文字å?を置換すると、å?のアドレスとずれるã?を防ぐ為ã€?
044             * 後ろから、置換を行いますã?ä¸?‹¬置換ã?、è¤?•°のæ–?­—å?置換をã€?–‹始アドレスの
045             * 後ろから、置換を始める為の、å?期データを登録しますã?
046             * 登録é ??、置換é?とは無関係に設定可能ですã?
047             *
048             * @param       start   置換開始アドレス
049             * @param       end     置換終äº?‚¢ドレス
050             * @param       newStr  置換文字å?
051             */
052            public void add( final int start, final int end, final String newStr ) {
053                    set.add( new ReplaceData( start, end, newStr ) );
054            }
055    
056            /**
057             * 置換å?æ–?­—å?を指定して、置換å?ç�?‚’実行しますã?
058             * add メソãƒ?ƒ‰でæŒ?®šした文字å?を実際に置換å?ç�?�—ますã?
059             *
060             * @param       target  置換å?æ–?­—å?
061             *
062             * @return      置換後文字å?
063             */
064            public String replaceAll( final String target ) {
065                    Iterator<ReplaceData> ite = set.iterator();
066                    StringBuilder buf = new StringBuilder( target );
067                    while( ite.hasNext() ) {
068                            ReplaceData data = ite.next();
069                            buf = data.replace( buf );
070                    }
071                    return buf.toString();
072            }
073    
074            /**
075             * 置換文字å?を管ç�?�™るå?部クラス
076             *
077             * @version  4.0
078             * @author       Kazuhiko Hasegawa
079             * @since    JDK5.0,
080             */
081            private static class ReplaceData implements Comparable<ReplaceData> {
082                    private final int start     ;
083                    private final int end       ;
084                    private final String newStr ;
085                    private final int hCode  ;
086    
087                    /**
088                     * 開始アドレス、終äº?‚¢ドレス、置換文字å?を指定しますã?
089                     * 通常、文字å?を置換すると、å?のアドレスとずれるã?を防ぐ為ã€?
090                     * 後ろから、置換を行いますã?ä¸?‹¬置換ã?、è¤?•°のæ–?­—å?置換をã€?–‹始アドレスの
091                     * 後ろから、置換を始める為の、å?期データを登録しますã?
092                     * 登録é ??、置換é?とは無関係に設定可能ですã?
093                     *
094                     * @param       start   置換開始アドレス
095                     * @param       end     置換終äº?‚¢ドレス
096                     * @param       newStr  置換文字å?
097                     */
098                    public ReplaceData( final int start, final int end, final String newStr ) {
099                            this.start  = start;
100                            this.end    = end;
101                            this.newStr = newStr ;
102                            hCode    = ( newStr + start + "_" + end ).hashCode();
103                    }
104    
105                    /**
106                     * 置換å?ç�?‚’実行しますã?
107                     *
108                     * @param   buf StringBuilder 入力文字å?
109                     * @return      出力文字å?
110                     */
111                    public StringBuilder replace( final StringBuilder buf ) {
112                            return buf.replace( start,end,newStr );
113                    }
114    
115                    /**
116                     * æŒ?®šã?ReplaceDataの開å§?終äº?�Œ重なってã�?‚‹かどã�?�‹を判定しますã?
117                     *                                                        return
118                     *                                   | o.E   S | E   o.S |
119                     * â‘?           S----E              |    ??  | 【<ã?  | false
120                     *                       o.S----o.E  |         |         |
121                     * ②            S----E              |    ??  |   ≧    | true
122                     *                 o.S----o.E        |         |         |
123                     * ③            S----E              |    ≧   |   ??   | true
124                     *         o.S----o.E                |         |         |
125                     * ④            S----E              |  【<ã? |   ??   | false
126                     *   o.S----o.E                      |         |         |
127                     *
128                     * @og.rev 5.7.2.1 (2014/01/17) 判定結果の true/false が反転してã�?�Ÿので、修正
129                     *
130                     * @param   other ReplaceData 入力文字å?
131                     * @return      オーバã?ラãƒ??してã�?‚‹かどã�?�‹(true:不正/false:正常)
132                     */
133                    public boolean isOverlap( final ReplaceData other ) {
134    //                      return  ! ( ( other == null ) || ( other.end < start ) || ( end < other.start ) );
135    //                      return  ( ( other == null ) || ( other.end < start ) || ( end < other.start ) );
136                            return  ( other == null ) || ! ( ( other.end < start ) || ( end < other.start ) );
137                    }
138    
139                    /**
140                     * 自然比è¼?ƒ¡ソãƒ?ƒ‰
141                     * インタフェース Comparable の 実è£?�§すã?
142                     * 登録された開始アドレスの降é?になるよã�?�«比è¼?�—ますã?
143                     * なおã?比è¼?¯¾照オブジェクトとオーバã?ラãƒ??してã�?‚‹場合ã?ã€?
144                     * 比è¼?�§きなã�?�¨して、IllegalArgumentException を発行しますã?
145                     *
146                     * @og.rev 5.7.4.0 (2014/03/07) 同ä¸?‚ªブジェクトã?判定を追åŠ?
147                     *
148                     * @param   other 比è¼?¯¾象のObject
149                     * @return  開始アドレスの降é?(自åˆ??アドレスが小さã�??合ã?ã€?¼?
150                     * @throws      IllegalArgumentException  引数オブジェクトがオーバã?ラãƒ??してã�?‚‹場å�?
151                     */
152                    public int compareTo( final ReplaceData other ) {
153                            if( other == null ) {
154                                    String errMsg = "引数に null は設定できませんã€? ;
155                                    throw new IllegalArgumentException( errMsg );
156                            }
157    
158                            // 5.7.4.0 (2014/03/07) 同ä¸?‚ªブジェクトã?判定を追åŠ?
159                            if( other.hCode == hCode ) { return 0; }
160    
161                            if( isOverlap( other) ) {
162                                    String errMsg = "比è¼?¯¾照オブジェクトとオーバã?ラãƒ??してã�?�¾すã?"
163                                                            + " this =[" + start + "],[" + end + "],[" + newStr + "]"
164                                                            + " other=[" + other.start + "],[" + other.end + "],[" + other.newStr + "]" ;
165                                    throw new IllegalArgumentException( errMsg );
166                            }
167                            return other.start - start;             // 開始é?の降é?
168                    }
169    
170                    /**
171                     * こã?オブジェクトと他ã?オブジェクトが等しã�?�‹どã�?�‹を示しますã?
172                     * インタフェース Comparable の 実è£?�«関連して、å?定義してã�?�¾すã?
173                     *
174                     * @param   other 比è¼?¯¾象の参ç?オブジェクãƒ?
175                     * @return  obj 引数にæŒ?®šされたオブジェクトとこã?オブジェクトが等しã�??合ã? true、そã�?�§なã�??合ã? false
176                     *
177                     */
178                    public boolean equals( final Object object ) {
179                            if( object instanceof ReplaceData ) {
180                                    ReplaceData other = (ReplaceData)object ;
181                                    return start == other.start &&
182                                                    end == other.end    &&
183                                                    newStr.equals( other.newStr ) ;
184                            }
185                            return false ;
186                    }
187    
188                    /**
189                     * オブジェクトã?ハッシュコードå?を返しますã?
190                     * こã?メソãƒ?ƒ‰は、java.util.Hashtable によって提供されるような
191                     * ハッシュãƒ??ブルで使用するために用意されてã�?�¾すã?
192                     * equals( Object ) メソãƒ?ƒ‰をオーバã?ライトしたå?合ã?、hashCode() メソãƒ?ƒ‰ã‚?
193                     * å¿?�š 記述するå¿?¦�がありますã?
194                     *
195                     *
196                     * @return  こã?オブジェクトã?ハッシュコードå?
197                     *
198                     */
199                    public int hashCode() {
200                            return hCode ;
201                    }
202            }
203    }