├── .gitignore ├── bin ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── go ├── release-snapshot.sh ├── gradlew.bat └── gradlew └── src ├── test └── java │ └── de │ └── otto │ └── sluggify │ └── SluggifyTest.java └── main └── java └── de └── otto └── sluggify └── Sluggify.java /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | out 4 | build 5 | *.iml 6 | *.ipr 7 | *.iws 8 | -------------------------------------------------------------------------------- /bin/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/otto-de-legacy/sluggify/master/bin/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /bin/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jun 24 16:02:14 CEST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=http\://services.gradle.org/distributions/gradle-2.4-bin.zip 7 | -------------------------------------------------------------------------------- /bin/go: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | b=`tput bold` 4 | nb=`tput sgr0` 5 | SCRIPT_DIR=$(dirname $0) 6 | GRADLEW=${SCRIPT_DIR}/gradlew 7 | function echob { 8 | echo "${b}${1}${nb}" 9 | } 10 | 11 | 12 | function release { 13 | ${SCRIPT_DIR}/release-snapshot.sh 14 | } 15 | 16 | function help { 17 | echo "usage: $0 18 | task can be: 19 | help -- This help message 20 | release -- Release new SNAPSHOT 21 | check -- Run all tests 22 | clean -- Clean working directory 23 | cleanIdea -- Remove IntelliJ IDEA files 24 | idea -- Generate files for IntelliJ IDEA 25 | 26 | -- Anything else accepted by gradlew 27 | " 28 | } 29 | 30 | 31 | if [ "$1" == "help" ]; then 32 | help 33 | elif [ "$1" == "release" ]; then 34 | release 35 | else 36 | $GRADLEW $* 37 | fi 38 | 39 | 40 | -------------------------------------------------------------------------------- /bin/release-snapshot.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | USER_GRADLE_PROPERTIES=~/.gradle/gradle.properties 6 | 7 | check_configured() { 8 | grep -q $1 ${USER_GRADLE_PROPERTIES} || echo "$1 not configured in ${USER_GRADLE_PROPERTIES}. $2" 9 | } 10 | 11 | check_configuration() { 12 | if [ ! -f ${USER_GRADLE_PROPERTIES} ]; then 13 | echo "${USER_GRADLE_PROPERTIES} does not exist" 14 | exit 1 15 | fi 16 | 17 | check_configured "sonatypeUsername" "This is the username you use to authenticate with sonatype nexus (e.g. otto-de)" 18 | check_configured "sonatypePassword" "This is the password you use to authenticate with sonatype nexus (ask Guido or one of the developers)" 19 | check_configured "signing.secretKeyRingFile" "This is the gpg secret key file, e.g. ~/.gnupg/secring.gpg. If this doesn't exist, generate a key: gpg --gen-key" 20 | check_configured "signing.keyId" "This is the id of your key (e.g. 72FE5380). Use gpg --list-keys to find yours" 21 | check_configured "signing.password" "This is the password you defined for your gpg key" 22 | } 23 | 24 | check_configuration 25 | 26 | gradlew uploadArchives 27 | -------------------------------------------------------------------------------- /bin/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/test/java/de/otto/sluggify/SluggifyTest.java: -------------------------------------------------------------------------------- 1 | package de.otto.sluggify; 2 | 3 | import org.testng.annotations.Test; 4 | 5 | import static org.hamcrest.CoreMatchers.is; 6 | import static org.hamcrest.CoreMatchers.nullValue; 7 | import static org.hamcrest.MatcherAssert.assertThat; 8 | 9 | public class SluggifyTest { 10 | 11 | @Test 12 | public void shouldSluglifySomeText() { 13 | assertThat(Sluggify.sluggify("Schöne neue Röhrenjeans in Größe 42"), is("schoene-neue-roehrenjeans-in-groesse-42")); 14 | } 15 | 16 | @Test 17 | public void shouldSluglifySomeTextWithLeadingAndTrailingHyphen() { 18 | assertThat(Sluggify.sluggify("-Schöne neue Röhrenjeans in Größe 42-"), is("schoene-neue-roehrenjeans-in-groesse-42")); 19 | } 20 | 21 | @Test 22 | public void shouldSluggifyAmpersandCharacters() { 23 | assertThat(Sluggify.sluggify("Röhrenjeans & Wäsche"), is("roehrenjeans-waesche")); 24 | } 25 | 26 | @Test 27 | public void shouldSluggifyLeetHaxorSpeak() { 28 | assertThat(Sluggify.sluggify("-ĿēĚt^ħĂxôŔ-"), is("leet-haxor")); 29 | } 30 | 31 | @Test 32 | public void shouldRemoveSuccessiveHyphens() { 33 | assertThat(Sluggify.sluggify("Ŀē---Ět^-^ħĂx...ôŔ"), is("le-et-hax-or")); 34 | } 35 | 36 | @Test 37 | public void shouldNotReplaceUnderscores() { 38 | assertThat(Sluggify.sluggify("Under_Score"), is("under_score")); 39 | } 40 | 41 | @Test 42 | public void shouldRemoveOpastrophesBeforeLetterS() { 43 | assertThat(Sluggify.sluggify("Mom's pants"), is("moms-pants")); 44 | } 45 | 46 | @Test 47 | public void shouldReplaceOpastrophesWithDashIfNotFollowedByLetterS() { 48 | assertThat(Sluggify.sluggify("Turtles'pants are awkward'"), is("turtles-pants-are-awkward")); 49 | } 50 | 51 | @Test 52 | public void shouldSluggifyOtherSpecialLetters() { 53 | assertThat(Sluggify.sluggify("ťśšşŝșùŵýžĜ ĤÌĴĶÑŚÙŴÝŹ"), is("tsssssuwyzg-hijknsuwyz")); 54 | } 55 | 56 | @Test 57 | public void shouldSluggifySingleWeirdCharacter() { 58 | assertThat(Sluggify.sluggify("®"), is("")); 59 | } 60 | 61 | @Test 62 | public void shouldSlugifyNullsAndEmptyStrings() { 63 | assertThat(Sluggify.sluggify(null), is(nullValue())); 64 | assertThat(Sluggify.sluggify(""), is("")); 65 | } 66 | 67 | @Test 68 | public void slugifyPlusSymbol() throws Exception { 69 | assertThat(Sluggify.sluggify("A+"), is("aplus")); 70 | assertThat(Sluggify.sluggify("A++"), is("aplusplus")); 71 | assertThat(Sluggify.sluggify("A+++"), is("aplusplusplus")); 72 | } 73 | 74 | @Test 75 | public void slugifyMitLetztesZeichenAlsBindestrich() { 76 | assertThat(Sluggify.sluggify("David-schreibt-auch-einen-Test-"), is("david-schreibt-auch-einen-test")); 77 | } 78 | 79 | @Test 80 | public void slugifyMitSonderzeichen() { 81 | assertThat(Sluggify.sluggify("Haup(t)hose_+*~#'/-\"'un[d]so--Wahns{i}n.n;"), is("haup-t-hose_plus-un-d-so-wahns-i-n-n")); 82 | } 83 | 84 | @Test 85 | public void shouldSluggifyCategoryPath() { 86 | // given 87 | String categoryTitle = "Mode>Jungen>Mädchen>Schnürschuhe"; 88 | 89 | // when 90 | String path = Sluggify.sluggifyPath(categoryTitle, ">", "/"); 91 | 92 | // then 93 | assertThat(path.toString(), is("mode/jungen/maedchen/schnuerschuhe")); 94 | } 95 | 96 | @Test 97 | public void shouldSluggifyCategoryPathWithOnePathElement() { 98 | // given 99 | String categoryTitle = "Mode"; 100 | 101 | // when 102 | String path = Sluggify.sluggifyPath(categoryTitle, ">", "/"); 103 | 104 | // then 105 | assertThat(path.toString(), is("mode")); 106 | } 107 | 108 | @Test 109 | public void shouldSluggifyCategoryPathWithTwoEmptyPathElements() { 110 | // given 111 | String categoryTitle = "Mode>>"; 112 | 113 | // when 114 | String path = Sluggify.sluggifyPath(categoryTitle, ">", "/"); 115 | 116 | // then 117 | assertThat(path.toString(), is("mode//")); 118 | } 119 | } -------------------------------------------------------------------------------- /bin/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /src/main/java/de/otto/sluggify/Sluggify.java: -------------------------------------------------------------------------------- 1 | package de.otto.sluggify; 2 | 3 | import com.google.common.base.Joiner; 4 | import com.google.common.base.Splitter; 5 | import com.google.common.cache.CacheBuilder; 6 | import com.google.common.cache.CacheLoader; 7 | import com.google.common.cache.LoadingCache; 8 | 9 | import java.util.concurrent.ExecutionException; 10 | import java.util.concurrent.TimeUnit; 11 | import java.util.regex.Matcher; 12 | import java.util.regex.Pattern; 13 | 14 | import static com.google.common.collect.Iterables.transform; 15 | 16 | public class Sluggify { 17 | 18 | private static final LoadingCache slugifyCache = CacheBuilder. newBuilder() 19 | .maximumSize(10000) 20 | .expireAfterWrite(10, TimeUnit.MINUTES) 21 | .build(new CacheLoader() { 22 | @Override 23 | public String load(String key) throws Exception { 24 | return doSlugify(key); 25 | } 26 | }); 27 | 28 | public static boolean isEmpty(String stringToCheck) { 29 | return stringToCheck == null || stringToCheck.isEmpty(); 30 | } 31 | 32 | private static final Pattern SPECIAL_CHARACTERS_REGEX = Pattern.compile("\\W"); 33 | 34 | public static String removeSpecialCharactersAndConvertToLowercase(String input) { 35 | StringBuilder result = new StringBuilder(); 36 | Matcher matcher = SPECIAL_CHARACTERS_REGEX.matcher(input); 37 | int lastIdx = 0; 38 | while (matcher.find()) { 39 | int startIdx = matcher.start(); 40 | if (startIdx > lastIdx) { 41 | result.append(input.substring(lastIdx, startIdx).toLowerCase()); 42 | } 43 | char umlaut = matcher.group().charAt(0); 44 | String replacementString = replacementStringFor(umlaut); 45 | if (result.length() == 0 || !("-".equals(replacementString) && result.charAt(result.length() - 1) == '-')) { 46 | result.append(replacementString); 47 | } 48 | lastIdx = matcher.end(); 49 | } 50 | if (lastIdx < input.length()) { 51 | result.append(input.substring(lastIdx).toLowerCase()); 52 | } 53 | return result.toString(); 54 | } 55 | 56 | private static String replacementStringFor(char specialChar) { 57 | switch (specialChar) { 58 | case 'ä': 59 | case 'Ä': 60 | case 'æ': 61 | return "ae"; 62 | case 'ö': 63 | case 'Ö': 64 | return "oe"; 65 | case 'Ü': 66 | case 'ü': 67 | return "ue"; 68 | case 'ß': 69 | return "ss"; 70 | case 'À': 71 | case 'Á': 72 | case 'Â': 73 | case 'Ã': 74 | case 'Å': 75 | case 'Ā': 76 | case 'Ą': 77 | case 'Ă': 78 | case 'à': 79 | case 'á': 80 | case 'â': 81 | case 'ã': 82 | case 'å': 83 | case 'ā': 84 | case 'ą': 85 | case 'ă': 86 | return "a"; 87 | case 'ç': 88 | case 'ć': 89 | case 'č': 90 | case 'ĉ': 91 | case 'ċ': 92 | case 'Ç': 93 | case 'Ć': 94 | case 'Č': 95 | case 'Ĉ': 96 | case 'Ċ': 97 | return "c"; 98 | case 'ď': 99 | case 'đ': 100 | case 'ð': 101 | case 'Ď': 102 | case 'Đ': 103 | case 'Ð': 104 | return "d"; 105 | case 'È': 106 | case 'É': 107 | case 'Ê': 108 | case 'Ë': 109 | case 'Ē': 110 | case 'Ę': 111 | case 'Ě': 112 | case 'Ĕ': 113 | case 'Ė': 114 | case 'è': 115 | case 'é': 116 | case 'ê': 117 | case 'ë': 118 | case 'ē': 119 | case 'ę': 120 | case 'ě': 121 | case 'ĕ': 122 | case 'ė': 123 | return "e"; 124 | case 'ƒ': 125 | case 'ſ': 126 | return "f"; 127 | case 'Ġ': 128 | case 'Ģ': 129 | case 'Ĝ': 130 | case 'Ğ': 131 | case 'ĝ': 132 | case 'ğ': 133 | case 'ġ': 134 | case 'ģ': 135 | return "g"; 136 | case 'Ĥ': 137 | case 'Ħ': 138 | case 'ĥ': 139 | case 'ħ': 140 | return "h"; 141 | case 'Ì': 142 | case 'Í': 143 | case 'Î': 144 | case 'Ï': 145 | case 'Ī': 146 | case 'Ĩ': 147 | case 'Ĭ': 148 | case 'Į': 149 | case 'İ': 150 | case 'ì': 151 | case 'í': 152 | case 'î': 153 | case 'ï': 154 | case 'ī': 155 | case 'ĩ': 156 | case 'ĭ': 157 | case 'į': 158 | case 'ı': 159 | return "i"; 160 | case 'ij': 161 | return "ij"; 162 | case 'Ĵ': 163 | case 'ĵ': 164 | return "j"; 165 | case 'Ķ': 166 | case 'ķ': 167 | case 'ĸ': 168 | return "k"; 169 | case 'ł': 170 | case 'ľ': 171 | case 'ĺ': 172 | case 'ļ': 173 | case 'ŀ': 174 | case 'Ł': 175 | case 'Ľ': 176 | case 'Ĺ': 177 | case 'Ļ': 178 | case 'Ŀ': 179 | return "l"; 180 | case 'Ñ': 181 | case 'Ń': 182 | case 'Ň': 183 | case 'Ņ': 184 | case 'Ŋ': 185 | case 'ñ': 186 | case 'ń': 187 | case 'ň': 188 | case 'ņ': 189 | case 'ʼn': 190 | case 'ŋ': 191 | return "n"; 192 | case 'ò': 193 | case 'ó': 194 | case 'ô': 195 | case 'õ': 196 | case 'ø': 197 | case 'ō': 198 | case 'ő': 199 | case 'ŏ': 200 | case 'œ': 201 | case 'Ò': 202 | case 'Ó': 203 | case 'Ô': 204 | case 'Õ': 205 | case 'Ø': 206 | case 'Ō': 207 | case 'Ő': 208 | case 'Ŏ': 209 | return "o"; 210 | case 'Þ': 211 | case 'þ': 212 | return "p"; 213 | case 'ŕ': 214 | case 'ř': 215 | case 'ŗ': 216 | case 'Ŕ': 217 | case 'Ř': 218 | case 'Ŗ': 219 | return "r"; 220 | case 'Ś': 221 | case 'Š': 222 | case 'Ş': 223 | case 'Ŝ': 224 | case 'Ș': 225 | case 'ś': 226 | case 'š': 227 | case 'ş': 228 | case 'ŝ': 229 | case 'ș': 230 | return "s"; 231 | case 'ť': 232 | case 'ţ': 233 | case 'ŧ': 234 | case 'ț': 235 | return "t"; 236 | case 'Ù': 237 | case 'Ú': 238 | case 'Û': 239 | case 'Ū': 240 | case 'Ů': 241 | case 'Ű': 242 | case 'Ŭ': 243 | case 'Ũ': 244 | case 'Ų': 245 | case 'ù': 246 | case 'ú': 247 | case 'û': 248 | case 'ū': 249 | case 'ů': 250 | case 'ű': 251 | case 'ŭ': 252 | case 'ũ': 253 | case 'ų': 254 | return "u"; 255 | case 'Ŵ': 256 | case 'ŵ': 257 | return "w"; 258 | case 'Ý': 259 | case 'Ŷ': 260 | case 'Ÿ': 261 | case 'ý': 262 | case 'ÿ': 263 | case 'ŷ': 264 | return "y"; 265 | case 'Ź': 266 | case 'Ž': 267 | case 'Ż': 268 | case 'ž': 269 | case 'ż': 270 | case 'ź': 271 | return "z"; 272 | case '+': 273 | return "plus"; 274 | default: 275 | return "-"; 276 | } 277 | } 278 | 279 | public static String sluggify(String string) { 280 | if (isEmpty(string)) { 281 | return string; 282 | } 283 | 284 | try { 285 | return slugifyCache.get(string); 286 | } catch (ExecutionException e) { 287 | throw new RuntimeException(e); 288 | } 289 | } 290 | 291 | /** 292 | * Sluggify a path consisting of several path elements separated by a path separator. 293 | * That is, split path by separator, sluggify all the elements and then join the path back together. 294 | * 295 | * @param path path to sluggify 296 | * @param pathSeparator separator of path to sluggify 297 | * @param resultPathSeparator new separator to be used for the returned path 298 | * 299 | * @return the new sluggified path 300 | */ 301 | public static String sluggifyPath(final String path, 302 | final String pathSeparator, 303 | final String resultPathSeparator) { 304 | final Iterable parts = Splitter.on(pathSeparator).split(path); 305 | return Joiner.on(resultPathSeparator).join(transform(parts, input -> Sluggify.sluggify(input))); 306 | } 307 | 308 | private static String doSlugify(String string) { 309 | string = string.replaceAll("([a-z])'s([^a-z])", "$1s$2"); // WTF ? 310 | string = removeSpecialCharactersAndConvertToLowercase(string); 311 | 312 | string = string.replaceAll("-+$", "").replaceAll("^-+", ""); 313 | 314 | return string; 315 | } 316 | } --------------------------------------------------------------------------------