001 /* 002 * Copyright (C) 2006 The Guava Authors 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, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package com.google.common.base; 018 019 import com.google.common.annotations.GwtCompatible; 020 021 /** 022 * Utility class for converting between various ASCII case formats. 023 * 024 * @author Mike Bostock 025 * @since 1.0 026 */ 027 @GwtCompatible 028 public enum CaseFormat { 029 /** 030 * Hyphenated variable naming convention, e.g., "lower-hyphen". 031 */ 032 LOWER_HYPHEN(CharMatcher.is('-'), "-"), 033 034 /** 035 * C++ variable naming convention, e.g., "lower_underscore". 036 */ 037 LOWER_UNDERSCORE(CharMatcher.is('_'), "_"), 038 039 /** 040 * Java variable naming convention, e.g., "lowerCamel". 041 */ 042 LOWER_CAMEL(CharMatcher.inRange('A', 'Z'), ""), 043 044 /** 045 * Java and C++ class naming convention, e.g., "UpperCamel". 046 */ 047 UPPER_CAMEL(CharMatcher.inRange('A', 'Z'), ""), 048 049 /** 050 * Java and C++ constant naming convention, e.g., "UPPER_UNDERSCORE". 051 */ 052 UPPER_UNDERSCORE(CharMatcher.is('_'), "_"); 053 054 private final CharMatcher wordBoundary; 055 private final String wordSeparator; 056 057 CaseFormat(CharMatcher wordBoundary, String wordSeparator) { 058 this.wordBoundary = wordBoundary; 059 this.wordSeparator = wordSeparator; 060 } 061 062 /** 063 * Converts the specified {@code String s} from this format to the specified {@code format}. A 064 * "best effort" approach is taken; if {@code s} does not conform to the assumed format, then the 065 * behavior of this method is undefined but we make a reasonable effort at converting anyway. 066 */ 067 public String to(CaseFormat format, String s) { 068 if (format == null) { 069 throw new NullPointerException(); 070 } 071 if (s == null) { 072 throw new NullPointerException(); 073 } 074 075 if (format == this) { 076 return s; 077 } 078 079 /* optimize cases where no camel conversion is required */ 080 switch (this) { 081 case LOWER_HYPHEN: 082 switch (format) { 083 case LOWER_UNDERSCORE: 084 return s.replace('-', '_'); 085 case UPPER_UNDERSCORE: 086 return Ascii.toUpperCase(s.replace('-', '_')); 087 } 088 break; 089 case LOWER_UNDERSCORE: 090 switch (format) { 091 case LOWER_HYPHEN: 092 return s.replace('_', '-'); 093 case UPPER_UNDERSCORE: 094 return Ascii.toUpperCase(s); 095 } 096 break; 097 case UPPER_UNDERSCORE: 098 switch (format) { 099 case LOWER_HYPHEN: 100 return Ascii.toLowerCase(s.replace('_', '-')); 101 case LOWER_UNDERSCORE: 102 return Ascii.toLowerCase(s); 103 } 104 break; 105 } 106 107 // otherwise, deal with camel conversion 108 StringBuilder out = null; 109 int i = 0; 110 int j = -1; 111 while ((j = wordBoundary.indexIn(s, ++j)) != -1) { 112 if (i == 0) { 113 // include some extra space for separators 114 out = new StringBuilder(s.length() + 4 * wordSeparator.length()); 115 out.append(format.normalizeFirstWord(s.substring(i, j))); 116 } else { 117 out.append(format.normalizeWord(s.substring(i, j))); 118 } 119 out.append(format.wordSeparator); 120 i = j + wordSeparator.length(); 121 } 122 if (i == 0) { 123 return format.normalizeFirstWord(s); 124 } 125 out.append(format.normalizeWord(s.substring(i))); 126 return out.toString(); 127 } 128 129 private String normalizeFirstWord(String word) { 130 switch (this) { 131 case LOWER_CAMEL: 132 return Ascii.toLowerCase(word); 133 default: 134 return normalizeWord(word); 135 } 136 } 137 138 private String normalizeWord(String word) { 139 switch (this) { 140 case LOWER_HYPHEN: 141 return Ascii.toLowerCase(word); 142 case LOWER_UNDERSCORE: 143 return Ascii.toLowerCase(word); 144 case LOWER_CAMEL: 145 return firstCharOnlyToUpper(word); 146 case UPPER_CAMEL: 147 return firstCharOnlyToUpper(word); 148 case UPPER_UNDERSCORE: 149 return Ascii.toUpperCase(word); 150 } 151 throw new RuntimeException("unknown case: " + this); 152 } 153 154 private static String firstCharOnlyToUpper(String word) { 155 int length = word.length(); 156 if (length == 0) { 157 return word; 158 } 159 return new StringBuilder(length) 160 .append(Ascii.toUpperCase(word.charAt(0))) 161 .append(Ascii.toLowerCase(word.substring(1))) 162 .toString(); 163 } 164 }