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                     *
118                     * @og.rev 5.7.2.1 (2014/01/17) åˆ¤å®šçµæžœã® true/false ãŒå転ã—ã¦ã?Ÿã®ã§ã€ä¿®æ­£
119                     *
120                     * @param   other ReplaceData 入力文字å?
121                     * @return      オーãƒã?ラãƒ??ã—ã¦ã?‚‹ã‹ã©ã?‹(true:䏿­£/false:正常)
122                     */
123                    public boolean isOverlap( final ReplaceData other ) {
124    //                      return  ! ( ( other == null ) || ( other.end < start ) || ( end < other.start ) );
125    //                      return  ( ( other == null ) || ( other.end < start ) || ( end < other.start ) );
126                            return  ( other == null ) || ! ( ( other.end < start ) || ( end < other.start ) );
127    
128                    }
129    
130                    /**
131                     * 自然比è¼?ƒ¡ã‚½ãƒ?ƒ‰
132                     * インタフェース Comparable 㮠実è£?§ã™ã?
133                     * 登録ã•れãŸé–‹å§‹ã‚¢ãƒ‰ãƒ¬ã‚¹ã®é™é?ã«ãªã‚‹ã‚ˆã?«æ¯”è¼?—ã¾ã™ã?
134                     * ãªãŠã?比è¼?¯¾ç…§ã‚ªãƒ–ジェクトã¨ã‚ªãƒ¼ãƒã?ラãƒ??ã—ã¦ã?‚‹å ´åˆã?ã€?
135                     * 比è¼?§ããªã?¨ã—ã¦ã€IllegalArgumentException を発行ã—ã¾ã™ã?
136                     *
137                     * @og.rev 5.7.4.0 (2014/03/07) åŒä¸?‚ªãƒ–ジェクトã?判定を追åŠ?
138                     *
139                     * @param   other 比è¼?¯¾è±¡ã®Object
140                     * @return  開始アドレスã®é™é?(自åˆ??アドレスãŒå°ã•ã??åˆã?ã€?¼?
141                     * @throws      IllegalArgumentException  引数オブジェクトãŒã‚ªãƒ¼ãƒã?ラãƒ??ã—ã¦ã?‚‹å ´å?
142                     */
143                    public int compareTo( final ReplaceData other ) {
144                            if( other == null ) {
145                                    String errMsg = "引数㫠null ã¯è¨­å®šã§ãã¾ã›ã‚“ã€? ;
146                                    throw new IllegalArgumentException( errMsg );
147                            }
148    
149                            // 5.7.4.0 (2014/03/07) åŒä¸?‚ªãƒ–ジェクトã?判定を追åŠ?
150                            if( other.hCode == hCode ) { return 0; }
151    
152                            if( isOverlap( other) ) {
153                                    String errMsg = "比è¼?¯¾ç…§ã‚ªãƒ–ジェクトã¨ã‚ªãƒ¼ãƒã?ラãƒ??ã—ã¦ã?¾ã™ã?"
154                                                            + " this =[" + start + "],[" + end + "],[" + newStr + "]"
155                                                            + " other=[" + other.start + "],[" + other.end + "],[" + other.newStr + "]" ;
156                                    throw new IllegalArgumentException( errMsg );
157                            }
158                            return other.start - start;             // é–‹å§‹é?ã®é™é?
159                    }
160    
161                    /**
162                     * ã“ã?オブジェクトã¨ä»–ã?オブジェクトãŒç­‰ã—ã?‹ã©ã?‹ã‚’示ã—ã¾ã™ã?
163                     * インタフェース Comparable 㮠実è£?«é–¢é€£ã—ã¦ã€å?定義ã—ã¦ã?¾ã™ã?
164                     *
165                     * @param   other 比è¼?¯¾è±¡ã®å‚ç?オブジェクãƒ?
166                     * @return  obj å¼•æ•°ã«æŒ?®šã•れãŸã‚ªãƒ–ジェクトã¨ã“ã?オブジェクトãŒç­‰ã—ã??åˆã? trueã€ãã?§ãªã??åˆã? false
167                     *
168                     */
169                    public boolean equals( final Object object ) {
170                            if( object instanceof ReplaceData ) {
171                                    ReplaceData other = (ReplaceData)object ;
172                                    return start == other.start &&
173                                                    end == other.end    &&
174                                                    newStr.equals( other.newStr ) ;
175                            }
176                            return false ;
177                    }
178    
179                    /**
180                     * オブジェクトã?ãƒãƒƒã‚·ãƒ¥ã‚³ãƒ¼ãƒ‰å?ã‚’è¿”ã—ã¾ã™ã?
181                     * ã“ã?メソãƒ?ƒ‰ã¯ã€java.util.Hashtable ã«ã‚ˆã£ã¦æä¾›ã•れるよã†ãª
182                     * ãƒãƒƒã‚·ãƒ¥ãƒ??ブルã§ä½¿ç”¨ã™ã‚‹ãŸã‚ã«ç”¨æ„ã•れã¦ã?¾ã™ã?
183                     * equals( Object ) メソãƒ?ƒ‰ã‚’オーãƒã?ライトã—ãŸå?åˆã?ã€hashCode() メソãƒ?ƒ‰ã‚?
184                     * å¿?š 記述ã™ã‚‹å¿?¦ãŒã‚りã¾ã™ã?
185                     *
186                     *
187                     * @return  ã“ã?オブジェクトã?ãƒãƒƒã‚·ãƒ¥ã‚³ãƒ¼ãƒ‰å?
188                     *
189                     */
190                    public int hashCode() {
191                            return hCode ;
192                    }
193            }
194    }