View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package org.jboss.netty.util.internal;
17  
18  import java.util.ArrayList;
19  import java.util.Formatter;
20  import java.util.List;
21  
22  /**
23   * String utility class.
24   */
25  public final class StringUtil {
26  
27      private StringUtil() {
28          // Unused.
29      }
30  
31      public static final String NEWLINE;
32  
33      static {
34          String newLine;
35  
36          try {
37              newLine = new Formatter().format("%n").toString();
38          } catch (Exception e) {
39              newLine = "\n";
40          }
41  
42          NEWLINE = newLine;
43      }
44  
45      /**
46       * Strip an Object of it's ISO control characters.
47       *
48       * @param value
49       *          The Object that should be stripped. This objects toString method will
50       *          called and the result passed to {@link #stripControlCharacters(String)}.
51       * @return {@code String}
52       *          A new String instance with its hexadecimal control characters replaced
53       *          by a space. Or the unmodified String if it does not contain any ISO
54       *          control characters.
55       */
56      public static String stripControlCharacters(Object value) {
57          if (value == null) {
58              return null;
59          }
60  
61          return stripControlCharacters(value.toString());
62      }
63  
64      /**
65       * Strip a String of it's ISO control characters.
66       *
67       * @param value
68       *          The String that should be stripped.
69       * @return {@code String}
70       *          A new String instance with its hexadecimal control characters replaced
71       *          by a space. Or the unmodified String if it does not contain any ISO
72       *          control characters.
73       */
74      public static String stripControlCharacters(String value) {
75          if (value == null) {
76              return null;
77          }
78  
79          boolean hasControlChars = false;
80          for (int i = value.length() - 1; i >= 0; i --) {
81              if (Character.isISOControl(value.charAt(i))) {
82                  hasControlChars = true;
83                  break;
84              }
85          }
86  
87          if (!hasControlChars) {
88              return value;
89          }
90  
91          StringBuilder buf = new StringBuilder(value.length());
92          int i = 0;
93  
94          // Skip initial control characters (i.e. left trim)
95          for (; i < value.length(); i ++) {
96              if (!Character.isISOControl(value.charAt(i))) {
97                  break;
98              }
99          }
100 
101         // Copy non control characters and substitute control characters with
102         // a space.  The last control characters are trimmed.
103         boolean suppressingControlChars = false;
104         for (; i < value.length(); i ++) {
105             if (Character.isISOControl(value.charAt(i))) {
106                 suppressingControlChars = true;
107                 continue;
108             } else {
109                 if (suppressingControlChars) {
110                     suppressingControlChars = false;
111                     buf.append(' ');
112                 }
113                 buf.append(value.charAt(i));
114             }
115         }
116 
117         return buf.toString();
118     }
119 
120     private static final String EMPTY_STRING = "";
121 
122     /**
123      * Splits the specified {@link String} with the specified delimiter.  This operation is a simplified and optimized
124      * version of {@link String#split(String)}.
125      */
126     public static String[] split(String value, char delim) {
127         final int end = value.length();
128         final List<String> res = new ArrayList<String>();
129 
130         int start = 0;
131         for (int i = 0; i < end; i ++) {
132             if (value.charAt(i) == delim) {
133                 if (start == i) {
134                     res.add(EMPTY_STRING);
135                 } else {
136                     res.add(value.substring(start, i));
137                 }
138                 start = i + 1;
139             }
140         }
141 
142         if (start == 0) { // If no delimiter was found in the value
143             res.add(value);
144         } else {
145             if (start != end) {
146                 // Add the last element if it's not empty.
147                 res.add(value.substring(start, end));
148             } else {
149                 // Truncate trailing empty elements.
150                 for (int i = res.size() - 1; i >= 0; i --) {
151                     if (res.get(i).length() == 0) {
152                         res.remove(i);
153                     } else {
154                         break;
155                     }
156                 }
157             }
158         }
159 
160         return res.toArray(new String[res.size()]);
161     }
162 
163     /**
164      * Splits the specified {@link String} with the specified delimiter in maxParts maximum parts.
165      * This operation is a simplified and optimized
166      * version of {@link String#split(String, int)}.
167      */
168     public static String[] split(String value, char delim, int maxParts) {
169         final int end = value.length();
170         final List<String> res = new ArrayList<String>();
171 
172         int start = 0;
173         int cpt = 1;
174         for (int i = 0; i < end && cpt < maxParts; i ++) {
175             if (value.charAt(i) == delim) {
176                 if (start == i) {
177                     res.add(EMPTY_STRING);
178                 } else {
179                     res.add(value.substring(start, i));
180                 }
181                 start = i + 1;
182                 cpt++;
183             }
184         }
185 
186         if (start == 0) { // If no delimiter was found in the value
187             res.add(value);
188         } else {
189             if (start != end) {
190                 // Add the last element if it's not empty.
191                 res.add(value.substring(start, end));
192             } else {
193                 // Truncate trailing empty elements.
194                 for (int i = res.size() - 1; i >= 0; i --) {
195                     if (res.get(i).length() == 0) {
196                         res.remove(i);
197                     } else {
198                         break;
199                     }
200                 }
201             }
202         }
203 
204         return res.toArray(new String[res.size()]);
205     }
206 
207     /**
208      * Get the item after one char delim if the delim is found (else null).
209      * This operation is a simplified and optimized
210      * version of {@link String#split(String, int)}.
211      */
212     public static String substringAfter(String value, char delim) {
213         int pos = value.indexOf(delim);
214         if (pos >= 0) {
215             return value.substring(pos + 1);
216         }
217         return null;
218     }
219 }