Cách đơn giản nhất để chuyển đổi một chuỗi Java từ tất cả các chữ hoa (các từ được phân tách bằng dấu gạch dưới) thành CamelCase (không có dấu tách từ) là gì?


152

Tiêu đề khá nhiều nói lên tất cả. Cách đơn giản / thanh lịch nhất mà tôi có thể chuyển đổi, trong Java, một chuỗi từ định dạng "THIS_IS_AN_EXAMPLE_STRING"sang định dạng " ThisIsAnExampleString" là gì? Tôi nghĩ rằng phải có ít nhất một cách để làm điều đó bằng cách sử dụng String.replaceAll()và một biểu thức chính quy.

Suy nghĩ ban đầu của tôi là: chuẩn bị chuỗi bằng dấu gạch dưới ( _), chuyển đổi toàn bộ chuỗi thành chữ thường và sau đó sử dụng thay thế All để chuyển đổi mọi ký tự đứng trước dấu gạch dưới với phiên bản chữ hoa.


12
Lưu ý của biên tập viên, 2015/03: "những suy nghĩ ban đầu" ở trên là siêu ngớ ngẩn. Bạn học được rất nhiều về xây dựng phần mềm trong sáu năm.
Matt Ball

4
Khoảnh khắc đó khi bạn hỏi 'thằng ngốc nào đã viết cái này' và nhìn vào kiểm soát nguồn để thấy rằng bạn trẻ, ngu ngốc đã làm. Đã từng trải qua rồi.
bến tàu

@MattBall: Tôi thích phiên bản suy nghĩ ban đầu, nó không yêu cầu thư viện và chỉ cần nối chuỗi và hai thay thế regex.
Konrad Höffner

Câu trả lời:


192

Một tùy chọn khác là sử dụng Google Guava's com.google.common.base.CaseFormat

George Hawkins đã để lại một bình luận với ví dụ về việc sử dụng này:

CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "THIS_IS_AN_EXAMPLE_STRING");

3
Tham khảo nhận xét của George Hawkins [người dùng: 245602] để biết ví dụ. stackoverflow.com/questions/1143951/
Mạnh

5
Tôi nhớ các câu trả lời java thuần túy khi tôi đang phát triển cho Android.
eliocs

1
Câu trả lời này là hữu ích nhất đối với tôi. Tôi rất có thể viết mã của riêng mình, nhưng nếu người khác đã có, tôi chắc chắn không muốn phát minh lại bánh xe.
James Dunn


1
@ CléssioMendes bạn đã xem xét việc này tại github.com/google/guava/issues chưa?
Arnout Engelen

128

Hãy xem WordUtils trong thư viện lang Apache Commons :

Cụ thể, phương thức capitalizeFully (String str, char [] delimiter) sẽ thực hiện công việc:

String blah = "LORD_OF_THE_RINGS";
assertEquals("LordOfTheRings", WordUtils.capitalizeFully(blah, new char[]{'_'}).replaceAll("_", ""));

Thanh xanh!


55
Không, thưa ngài! Chúng ta nên tự viết lại các tiện ích đã có, đang hoạt động này, vì chúng ta là những lập trình viên phù hợp!
skaffman

24
Đó là 16:42 vào chiều thứ Sáu. Tôi sẽ để mọi người viết lại nó, tôi sẽ đi uống bia \ o /;)
Dan Gravell

1
Hơn nữa, tôi thậm chí không có quyền truy cập vào gói cụ thể đó với thiết lập hiện tại của mình và vì tôi thực sự không cần bất cứ thứ gì ngoài phương thức capitalizeFully, tôi không mất gì khi tự viết nó.
Matt Ball

7
Tôi tôn trọng quyết định của bạn Matt, có lẽ đó là điều đúng đắn để làm ở vị trí của bạn. Tuy nhiên, hãy xem xét những điều sau: * Một người khác trong nhóm của bạn quyết định họ cần một thói quen để trao đổi trường hợp các chữ cái. Họ thực hiện nó. Bây giờ bạn có ~ 20 dòng để duy trì. Bạn sẽ có ~ 2 nếu bạn sử dụng thư viện. Và đừng quên các bài kiểm tra đơn vị! * Câu trả lời được chấp nhận có một nhược điểm ở chỗ tên phương thức không mô tả những gì mã làm. Một API được tái sử dụng tốt như công cụ commons hiếm khi có những nhược điểm đó. Vấn đề là bảo trì là chi phí lớn nhất của phần mềm. Nói chung, sử dụng lại là một ý tưởng tốt.
Dan Gravell

2
Để "truy cập gói cụ thể này", hãy thả repo1.maven.org/maven2/commons-lang/commons-lang/2.5/ vào đường dẫn của bạn. Cổ vật Maven là commons-lang: commons-lang: 2.5 và nó có sẵn từ Maven Central.
Hendy I Girls

90
static String toCamelCase(String s){
   String[] parts = s.split("_");
   String camelCaseString = "";
   for (String part : parts){
      camelCaseString = camelCaseString + toProperCase(part);
   }
   return camelCaseString;
}

static String toProperCase(String s) {
    return s.substring(0, 1).toUpperCase() +
               s.substring(1).toLowerCase();
}

Lưu ý : Bạn cần thêm xác thực đối số.


1
Câu trả lời hay, nhưng sẽ tốt hơn một chút nếu tên phương thức mô tả thực tế là chuỗi bị tách hoặc logic đó được đưa ra ngoài và các cuộc gọi phương thức được căn chỉnh như một đường ống, ví dụ: "THIS_IS_AN_EXAMPLE_STRING" .removeUnderscores (). ToCamelCase (). được tái sử dụng nhiều hơn.
Dan Gravell

1
Điều đó không nhất thiết phải tốt hơn (mặc dù có, nó có thể tái sử dụng nhiều hơn). Khi nói đến các quy ước định dạng tên, camelcase có thể / không ngụ ý không sử dụng dấu gạch dưới; ở mặt trái của đồng tiền, có những quy ước chỉ định sử dụng dấu gạch dưới. Vì vậy, trong suy nghĩ của tôi, đây chỉ là một phương pháp để chuyển đổi từ định dạng này sang định dạng khác.
Matt Ball

58
Thư viện ổi của Google có một enum tiện ích chung hơn để chuyển đổi giữa các quy ước chung. Đối với trường hợp này, bạn sẽ làm String result = CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, "THIS_IS_AN_EXAMPLE_STRING");. Xem com.google.common.base.CaseFormat javadoc .
George Hawkins

1
Câu trả lời này sẽ gặp vấn đề khi được sử dụng ở các địa phương như Thổ Nhĩ Kỳ ... Nếu mã của bạn sẽ được sử dụng ở nhiều địa phương, hãy sử dụng toUpperCase (Locale) và toLowercase (Locale) .. không phải các mã phụ thuộc vào miền địa phương mặc định.
vkraemer

2
@DanGravell: một khi bạn loại bỏ các dấu gạch dưới, không còn có thể phân biệt các từ.
njzk2

18

Với Apache Commons Lang3 lib thì rất dễ dàng.

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;

public String getName(String text) {
  return StringUtils.remove(WordUtils.capitalizeFully(text, '_'), "_");
}

Thí dụ:

getName("SOME_CONSTANT");

Cung cấp:

"SomeConstant"

2
Trong trường hợp tên biến, điều này không hợp lệ vì tên phải bắt đầu bằng chữ thường.
16:00

9
public static void main(String[] args) {
    String start = "THIS_IS_A_TEST";
    StringBuffer sb = new StringBuffer();
    for (String s : start.split("_")) {
        sb.append(Character.toUpperCase(s.charAt(0)));
        if (s.length() > 1) {
            sb.append(s.substring(1, s.length()).toLowerCase());
        }
    }
    System.out.println(sb);
}

3
bài kiểm tra s.length không cần thiết
njzk2

9

Đây là một đoạn mã có thể giúp:

String input = "ABC_DEF";
StringBuilder sb = new StringBuilder();
for( String oneString : input.toLowerCase().split("_") )
{
    sb.append( oneString.substring(0,1).toUpperCase() );
    sb.append( oneString.substring(1) );
}

// sb now holds your desired String

Giải pháp này phù hợp với trường hợp ALL_UPPER sang Camel. Nhưng một thay đổi nhỏ trong chương trình cũng có thể xử lý MixED_case hoặc low_case (vỏ rắn). Tôi đã đề nghị chỉnh sửa nếu được phép.
sud007

6

Ví dụ Java 1.8 sử dụng Luồng

String text = "THIS_IS_SOME_TEXT";

String bactrianCamel = Stream.of(text.split("[^a-zA-Z0-9]"))
        .map(v -> v.substring(0, 1).toUpperCase() + v.substring(1).toLowerCase())
        .collect(Collectors.joining());
String dromedaryCamel = bactrianCamel.toLowerCase().substring(0, 1) + bactrianCamel.substring(1); 

System.out.printf("%s is now %s%n", text, dromedaryCamel); 

THIS_IS_SOME_TEXT hiện là thisIsSomeText


Tôi thích câu trả lời này, nhưng nó có một lỗ hổng nếu chuỗi đầu vào đã có trong trường hợp lạc đà, trong trường hợp đó nó hạ thấp toàn bộ đầu vào. ví dụ abcDef trở thành abcdef.
mrswadge

Một thử nghiệm sử dụng text.matches( "([a-z]+[a-zA-Z0-9]+)+" )trước khi vỏ lạc đà có lẽ là một cách giải quyết hợp lý cho vấn đề vỏ thấp hơn.
mrswadge

2

Không chắc chắn, nhưng tôi nghĩ rằng tôi có thể sử dụng ít bộ nhớ hơn và có được hiệu suất đáng tin cậy bằng cách thực hiện nó char-by-char. Tôi đã làm một cái gì đó tương tự, nhưng trong các vòng lặp trong các chủ đề nền, vì vậy bây giờ tôi đang thử điều này. Tôi đã có một số kinh nghiệm với String.split đắt hơn dự kiến. Và tôi đang làm việc trên Android và hy vọng các trục trặc của GC sẽ trở thành vấn đề sau đó sử dụng cpu.

  public static String toCamelCase(String value) {
    StringBuilder sb = new StringBuilder();

    final char delimChar = '_';
    boolean lower = false;
    for (int charInd = 0; charInd < value.length(); ++charInd) {
      final char valueChar = value.charAt(charInd);
      if (valueChar == delimChar) {
        lower = false;
      } else if (lower) {
        sb.append(Character.toLowerCase(valueChar));
      } else {
        sb.append(Character.toUpperCase(valueChar));
        lower = true;
      }
    }

    return sb.toString();
  }

Một gợi ý rằng String.split đắt tiền là đầu vào của nó là regex (không phải char như String.indexOf) và nó trả về một mảng (thay vì nói iterator vì vòng lặp chỉ sử dụng một thứ tại một thời điểm). Ngoài ra, các trường hợp như "AB_AB_AB_AB_AB_AB ..." phá vỡ hiệu quả của bất kỳ bản sao số lượng lớn nào và đối với các chuỗi dài sử dụng một thứ tự cường độ bộ nhớ lớn hơn chuỗi đầu vào.

Trong khi vòng lặp thông qua ký tự không có trường hợp chính tắc. Vì vậy, với tôi chi phí của một regex không cần thiết và mảng có vẻ ít được ưa thích hơn (sau đó từ bỏ hiệu quả sao chép số lượng lớn có thể). Quan tâm để nghe ý kiến ​​/ sửa chữa, cảm ơn.


2
public String withChars(String inputa) {
    String input = inputa.toLowerCase();
    StringBuilder sb = new StringBuilder();
    final char delim = '_';
    char value;
    boolean capitalize = false;
    for (int i=0; i<input.length(); ++i) {
        value = input.charAt(i);
        if (value == delim) {
            capitalize = true;
        }
        else if (capitalize) {
            sb.append(Character.toUpperCase(value));
            capitalize = false;
        }
        else {
            sb.append(value);
        }
    }

    return sb.toString();
}

public String withRegex(String inputa) {
    String input = inputa.toLowerCase();
    String[] parts = input.split("_");
    StringBuilder sb = new StringBuilder();
    sb.append(parts[0]);
    for (int i=1; i<parts.length; ++i) {
        sb.append(parts[i].substring(0,1).toUpperCase());
        sb.append(parts[i].substring(1));
    }

    return sb.toString();
}

Thời gian: tính bằng mili giây.

Iterations = 1000
WithChars: start = 1379685214671 end = 1379685214683 diff = 12
WithRegex: start = 1379685214683 end = 1379685214712 diff = 29

Iterations = 1000
WithChars: start = 1379685217033 end = 1379685217045 diff = 12
WithRegex: start = 1379685217045 end = 1379685217077 diff = 32

Iterations = 1000
WithChars: start = 1379685218643 end = 1379685218654 diff = 11
WithRegex: start = 1379685218655 end = 1379685218684 diff = 29

Iterations = 1000000
WithChars: start = 1379685232767 end = 1379685232968 diff = 201
WithRegex: start = 1379685232968 end = 1379685233649 diff = 681

Iterations = 1000000
WithChars: start = 1379685237220 end = 1379685237419 diff = 199
WithRegex: start = 1379685237419 end = 1379685238088 diff = 669

Iterations = 1000000
WithChars: start = 1379685239690 end = 1379685239889 diff = 199
WithRegex: start = 1379685239890 end = 1379685240585 diff = 695

Iterations = 1000000000
WithChars: start = 1379685267523 end = 1379685397604 diff = 130081
WithRegex: start = 1379685397605 end = 1379685850582 diff = 452977

Thật tuyệt, đó có phải là lặp đi lặp lại với đầu vào "THIS_IS_AN_EXAMPLE_STRING" không?
leorleor

@leorleor Lặp lại = 1000000000 WithChars: start = 1387547394726 end = 1387547889896 diff = 495170 WithRegex: start = 1387547889897 end = 1387548944739 diff = 1054842
Srisa

1

Bạn có thể sử dụng org.modeshape.common.text.Inflector .

Đặc biệt:

String camelCase(String lowerCaseAndUnderscoredWord,
    boolean uppercaseFirstLetter, char... delimiterChars) 

Theo mặc định, phương thức này chuyển đổi chuỗi thành UpperCamelCase.

Cổ vật của Maven là: org.modeshape: modeshape-common: 2.3.0.Final

trên kho JBoss: https://reposective.jboss.org/nexus/content/repos khu /

Đây là tệp JAR: https://reposective.jboss.org/nexus/content/repos khu /ở / nah


1

Bạn cũng có thể thử điều này:

 public static String convertToNameCase(String s)
    {
        if (s != null)
        {
            StringBuilder b = new StringBuilder();
            String[] split = s.split(" ");
            for (String srt : split)
            {
                if (srt.length() > 0)
                {
                    b.append(srt.substring(0, 1).toUpperCase()).append(srt.substring(1).toLowerCase()).append(" ");
                }
            }
            return b.toString().trim();
        }
        return s;
    }

1
protected String toCamelCase(String input) {
    if (input == null) {
        return null;
    }

    if (input.length() == 0) {
        return "";
    }

    // lowercase the first character
    String camelCaseStr = input.substring(0, 1).toLowerCase();

    if (input.length() > 1) {
        boolean isStartOfWord = false;

        for (int i = 1; i < input.length(); i++) {
            char currChar = input.charAt(i);
            if (currChar == '_') {
                // new word. ignore underscore
                isStartOfWord = true;
            } else if (Character.isUpperCase(currChar)) {
                // capital letter. if start of word, keep it
                if (isStartOfWord) {
                    camelCaseStr += currChar;
                } else {
                    camelCaseStr += Character.toLowerCase(currChar);
                }
                isStartOfWord = false;
            } else {
                camelCaseStr += currChar;
                isStartOfWord = false;
            }
        }
    }

    return camelCaseStr;
}

1
public String CamelCase(String str)
{
    String CamelCase="";
    String parts[] = str.split("_");
    for(String part:parts)
    {
        String as=part.toLowerCase();
        int a=as.length();
        CamelCase = CamelCase + as.substring(0, 1).toUpperCase()+ as.substring(1,a);    
    }
    return CamelCase;
}

Đây là Chương trình đơn giản nhất để chuyển đổi thành CamelCase. hy vọng nó sẽ giúp bạn ..


0

Nó sẽ chuyển đổi Enum Constantthành Camel Case. Nó sẽ hữu ích cho bất cứ ai đang tìm kiếm funtionality như vậy.

public enum TRANSLATE_LANGUAGES {
        ARABIC("ar"), BULGARIAN("bg"), CATALAN("ca"), CHINESE_SIMPLIFIED("zh-CN"), CHINESE_TRADITIONAL("zh-TW"), CZECH("cs"), DANISH("da"), DUTCH("nl"), ENGLISH("en"), ESTONIAN("et"), FINNISH("fi"), FRENCH(
                "fr"), GERMAN("de"), GREEK("el"), HAITIAN_CREOLE("ht"), HEBREW("he"), HINDI("hi"), HMONG_DAW("mww"), HUNGARIAN("hu"), INDONESIAN("id"), ITALIAN("it"), JAPANESE("ja"), KOREAN("ko"), LATVIAN(
                "lv"), LITHUANIAN("lt"), MALAY("ms"), NORWEGIAN("no"), PERSIAN("fa"), POLISH("pl"), PORTUGUESE("pt"), ROMANIAN("ro"), RUSSIAN("ru"), SLOVAK("sk"), SLOVENIAN("sl"), SPANISH("es"), SWEDISH(
                "sv"), THAI("th"), TURKISH("tr"), UKRAINIAN("uk"), URDU("ur"), VIETNAMESE("vi");

        private String code;

        TRANSLATE_LANGUAGES(String language) {
            this.code = language;
        }

        public String langCode() {
            return this.code;
        }

        public String toCamelCase(TRANSLATE_LANGUAGES lang) {
            String toString = lang.toString();
            if (toString.contains("_")) {
                String st = toUpperLowerCase(toString.split("_"));
            }

            return "";
        }

        private String toUpperLowerCase(String[] tempString) {
            StringBuilder builder = new StringBuilder();

            for (String temp : tempString) {

                String char1 = temp.substring(0, 1);
                String restString = temp.substring(1, temp.length()).toLowerCase();
                builder.append(char1).append(restString).append(" ");

            }

            return builder.toString();
        }
    }

0

Một giải pháp nữa cho điều này có thể như sau.

public static String toCamelCase(String str, String... separators) {
    String separatorsRegex = "\\".concat(org.apache.commons.lang3.StringUtils.join(separators, "|\\"));
    List splits = Arrays.asList(str.toLowerCase().split(separatorsRegex));
    String capitalizedString = (String)splits.stream().map(WordUtils::capitalize).reduce("", String::concat);
    return capitalizedString.substring(0, 1).toLowerCase() + capitalizedString.substring(1);
}

0
public static final String  UPPER_CAMEL = "initUp";
public static final String  LOWER_CAMEL = "initLow";

public String toCamel(String src, String separator, String format) {
    StringBuilder builder = new StringBuilder(src.toLowerCase());
    int len = builder.length();

    for (int idx = builder.indexOf(separator); idx > 0 && idx < len; idx = builder.indexOf(separator, idx)) {
        builder = builder.replace(idx, idx + 2, (String.valueOf(builder.charAt(idx + 1)).toUpperCase()));
    }

    switch (format) {
    case LOWER_CAMEL:
        builder.setCharAt(0, Character.toLowerCase(builder.charAt(0)));
        break;
    default:
        builder.setCharAt(0, Character.toUpperCase(builder.charAt(0)));
        break;
    }

    return builder.toString();

}

Cầu nguyện như

toCamel("THIS_IS_AN_EXAMPLE_STRING", "_", UPPER_CAMEL)

Thời gian thực hiện: 14 ms


0

Một chiếc giày đơn giản:

 public static String camelCase(String in) {
    if (in == null || in.length() < 1) { return ""; } //validate in
    String out = "";
    for (String part : in.toLowerCase().split("_")) {
        if (part.length() < 1) { //validate length
            continue;
        }
        out += part.substring(0, 1).toUpperCase();
        if (part.length() > 1) { //validate length
            out += part.substring(1);
        }
    }
    return out;
}

-2

Java 8 cho nhiều chuỗi:

import com.google.common.base.CaseFormat;



String camelStrings = "YOUR_UPPER, YOUR_TURN, ALT_TAB";

List<String> camelList = Arrays.asList(camelStrings.split(","));
camelList.stream().forEach(i -> System.out.println(CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, i) + ", "));

1
Câu trả lời trùng lặp
Mark Jeronimus

-2
    protected String toCamelCase(CaseFormat caseFormat, String... words){
        if (words.length  == 0){
          throw new IllegalArgumentException("Word list is empty!");
        }

        String firstWord = words[0];
        String [] restOfWords = Arrays.copyOfRange(words, 1, words.length);

        StringBuffer buffer = new StringBuffer();
        buffer.append(firstWord);
        Arrays.asList(restOfWords).stream().forEach(w->buffer.append("_"+ w.toUpperCase()));

        return CaseFormat.UPPER_UNDERSCORE.to(caseFormat, buffer.toString());

    }

1
CaseFormatkhông phải là API tiêu chuẩn. Câu trả lời trùng lặp nếu đó là quả ổi.
Mark Jeronimus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.