用于在 java 中将 CamelCase 转换为 camel_case 的正则表达式

Posted

技术标签:

【中文标题】用于在 java 中将 CamelCase 转换为 camel_case 的正则表达式【英文标题】:Regex for converting CamelCase to camel_case in java 【发布时间】:2012-05-05 19:44:05 【问题描述】:

我理解为什么使用正则表达式将FooBar 之类的字符串转换为Foo_Bar 时没有给出所需的输出,而是给出了Foo_Bar_。我可以用 String.substring substring(0, string.length() - 2) 做点什么,或者只是替换最后一个字符,但我认为对于这种情况有更好的解决方案。

代码如下:

String regex = "([A-Z][a-z]+)";
String replacement = "$1_";

"CamelCaseToSomethingElse".replaceAll(regex, replacement); 

/*
outputs: Camel_Case_To_Something_Else_
desired output: Camel_Case_To_Something_Else
*/

问题:正在寻找一种更简洁的方法来获得所需的输出?

【问题讨论】:

这个问题类似于***.com/questions/4886091/… 【参考方案1】:

您可以使用来自 Java 8 的 Stream API 和来自 commons-lang 的方法 StringUtils.capitalize(..) 轻松地将字符串转换为驼峰式大小写

 public String toCamelCase(String str) 
    return Arrays.stream(str.split("_"))
        .map(StringUtils::capitalize)
        .collect(Collectors.joining());

【讨论】:

【参考方案2】:

这是我的 3 个正则表达式的解决方案:

str.replaceAll("([^A-Z])([A-Z0-9])", "$1_$2") // standard replace
                   .replaceAll("([A-Z]+)([A-Z0-9][^A-Z]+)", "$1_$2") // last letter after full uppercase.
                    .replaceAll("([0-9]+)([a-zA-Z]+)", "$1_$2").toLowerCase(); // letters after numbers

结果:

thisIsATest: this_is_a_test
EndWithNumber3: end_with_number_3
3ThisStartWithNumber: 3_this_start_with_number
Number3InMiddle: number_3_in_middle
Number3inMiddleAgain: number_3_in_middle_again
MyUUIDNot: my_uuid_not
HOLAMundo: hola_mundo
holaMUNDO: hola_mundo
with_underscore: with_underscore
withAUniqueLetter: with_a_unique_letter

【讨论】:

【参考方案3】:

如果有人出于任何原因不想使用 Guava,我正在写这个答案。

CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "SomeInput");

在我们的案例中,我们遇到了存储问题。 Guava 还有一个特殊情况:如果我们将“Ph_D”作为输入,那么我们将得到带有两个下划线的“ph__d”。

只要我测试过,下面的代码就可以工作。

public static String camelCaseToLowerCaseWithUnderscore(String string) 
    if (string.matches(".*[a-z].*")) 
        final Matcher matcher = Pattern.compile("(_?[A-Z][a-z]?)").matcher(string);

        StringBuffer stringBuffer = new StringBuffer();
        matcher.find(); // This is just to escape the first group (beginning of string)
        while (matcher.find()) 
            final String group = matcher.group();
            if (!group.startsWith("_")) 
                matcher.appendReplacement(stringBuffer, "_" + group);
            
        
        matcher.appendTail(stringBuffer);
        return stringBuffer.toString().toLowerCase();
    
    else 
        return string;
    

【讨论】:

【参考方案4】:

不确定是否有可能使用纯正则表达式实现真正可靠的东西。尤其是支持首字母缩略词。

我做了一个小函数,受@radzimir 答案的启发,支持首字母缩略词,没有字母字符:

来自https://gist.github.com/ebuildy/cf46a09b1ac43eea17c7621b7617ebcd:

private static String snakeCaseFormat(String name) 
    final StringBuilder result = new StringBuilder();

    boolean lastUppercase = false;

    for (int i = 0; i < name.length(); i++) 
        char ch = name.charAt(i);
        char lastEntry = i == 0 ? 'X' : result.charAt(result.length() - 1);
        if (ch == ' ' || ch == '_' || ch == '-' || ch == '.') 
            lastUppercase = false;

            if (lastEntry == '_') 
                continue;
             else 
                ch = '_';
            
         else if (Character.isUpperCase(ch)) 
            ch = Character.toLowerCase(ch);
            // is start?
            if (i > 0) 
                if (lastUppercase) 
                    // test if end of acronym
                    if (i + 1 < name.length()) 
                        char next = name.charAt(i + 1);
                        if (!Character.isUpperCase(next) && Character.isAlphabetic(next)) 
                            // end of acronym
                            if (lastEntry != '_') 
                                result.append('_');
                            
                        
                    
                 else 
                    // last was lowercase, insert _
                    if (lastEntry != '_') 
                        result.append('_');
                    
                
            
            lastUppercase = true;
         else 
            lastUppercase = false;
        

        result.append(ch);
    
    return result.toString();

【讨论】:

这是一个高质量的答案,它可以处理大多数边缘情况。【参考方案5】:

看到这个question和CaseFormat from guava

在你的情况下,类似于:

CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "SomeInput");

【讨论】:

@eliocs 这个问题没有被标记为 android 和“更整洁的方式”。无论如何感谢您的反对 ;) CaseFormat 链接已离线。替换为here Guava 函数中有一个特殊情况,可能不是每个用户都想要的。如果我们有“Ph_D”,那么您将得到带有两个下划线的“ph__d”。我在这里写信给人们注意【参考方案6】:

我必须实现它以将驼峰格式的一些键转换为带下划线的小写。我想出的正则表达式是:

(?&lt;!^|_|[A-Z])([A-Z])

在英文中它代表前面没有字符串开头、下划线或其他大写字母的大写字母

在下面的示例中,粗体字符是应该使用上述正则表达式产生匹配的字符:

骆驼CaseToSsomethingElse 骆驼CaseToSsomethingElse camel_case_to_something_else Camel_Case_To_Something_Else CAMEL_CASE_TO_SOMETHING_ELSE

注意表达式不会影响已经是小写+下划线格式的字符串。

替换模式是:

_l$1

这意味着第一个捕获组的小写,第一个捕获组是大写字母。之后您也可以将整个字符串小写,以规范上面列表中的最后两个样本。

【讨论】:

【参考方案7】:

我无法提供正则表达式,反正它会非常复杂。

试试这个自动识别首字母缩写词的功能。

很遗憾,Guava lib 不会自动检测大写首字母缩写词,因此“bigCAT”将被转换为“BIG_C_A_T”

/**
 * Convert to UPPER_UNDERSCORE format detecting upper case acronyms
 */
private String upperUnderscoreWithAcronyms(String name) 
    StringBuffer result = new StringBuffer();
    boolean begin = true;
    boolean lastUppercase = false;
    for( int i=0; i < name.length(); i++ ) 
        char ch = name.charAt(i);
        if( Character.isUpperCase(ch) ) 
            // is start?
            if( begin ) 
                result.append(ch);
             else 
                if( lastUppercase ) 
                    // test if end of acronym
                    if( i+1<name.length() ) 
                        char next = name.charAt(i+1);
                        if( Character.isUpperCase(next) ) 
                            // acronym continues
                            result.append(ch);
                         else 
                            // end of acronym
                            result.append('_').append(ch);
                        
                     else 
                        // acronym continues
                        result.append(ch);
                    
                 else 
                    // last was lowercase, insert _
                    result.append('_').append(ch);
                
            
            lastUppercase=true;
         else 
            result.append(Character.toUpperCase(ch));
            lastUppercase=false;
        
        begin=false;
    
    return result.toString();

【讨论】:

【参考方案8】:
public class ReplaceFromCameltoSnake 
    public static void main(String args[])
        String s1=" totalAmountWithoutDiscount";  
        String replaceString=s1.replaceAll("([A-Z]+)","\\_$1").toLowerCase(); 
        System.out.println(replaceString);  
    

【讨论】:

$1-用来组团【参考方案9】:

将小写和大写分成两组,就可以了

public  class Main

    public static void main(String args[])
    
        String regex = "([a-z])([A-Z]+)";
        String replacement = "$1_$2";
        System.out.println("CamelCaseToSomethingElse"
                           .replaceAll(regex, replacement)
                           .toLowerCase());
    

【讨论】:

注意:如果输入字符串中允许单字母单词,例如“thisIsATest”,上面的代码将打印“this_is_atest”。番石榴,在接受的答案中,结果是“this_is_a_test”。 这不适用于以大写字母开头的名称,例如:IBMIsMyCompany【参考方案10】:

你可以使用下面的代码sn-p:

String replaceAll = key.replaceAll("(.)(\\pUpper)", "$1_$2").toLowerCase();

【讨论】:

如果我的字符串包含一个数字怎么办 - mode3 以 mode3 结尾,而我想要 mode_3。 它不会像 MyUUID 这样将骆驼大小写正确地转换为下划线,我得到了 my_uu_id @Mike/@User3301 试试这个String replaceAll = key.replaceAll("(.)(\\pUpper+|\\d+)", "$1_$2").toLowerCase();【参考方案11】:

为什么不简单地将前面的字符匹配为非行首$

String text = "CamelCaseToSomethingElse";
System.out.println(text.replaceAll("([^_A-Z])([A-Z])", "$1_$2"));

请注意,此版本可以安全地用于已装骆驼皮的东西。

【讨论】:

您是否尝试使用^$ 作为锚点?因为当您将它们放入字符类时,它们的含义会发生变化。 [^$_A-Z] 匹配任何不是$_ 或大写字母的字符,我认为这不是您的意思。 不打算作为锚点,我试图不匹配大写字符,$ 被错误地添加,因为它是我在类名上使用的一种技术。【参考方案12】:

添加一个零宽度的前瞻断言。

http://docs.oracle.com/javase/6/docs/api/java/util/regex/Pattern.html

阅读(?=X) 等的文档。

就个人而言,我实际上会拆分字符串,然后重新组合它。如果做得好,这甚至可能更快,并且它使代码比正则表达式更容易理解。不要误会我的意思:我喜欢正则表达式。但这并不是一个真正简洁的正则表达式,这个transformation 也不是一个经典的正则表达式任务。毕竟你似乎也想做小写?

一个丑陋但快速的技巧是将(.)([A-Z]+)替换为$1_$2,然后将整个字符串小写(除非您可以执行perl风格的扩展正则表达式,您可以直接将替换小写!)。我仍然认为在从低到高的过渡中拆分,然后转换,然后加入是这样做的正确和最易读的方式。

【讨论】:

是的,最终我也希望它是小写的。 所以我会把它分成匹配[A-Z][a-z]*的块,小写第一个字母,然后重新加入它们。或者我刚刚添加到主要回复中的替换+小写技巧。【参考方案13】:
([A-Z][a-z\d]+)(?=([A-Z][a-z\d]+))

应搜索大写字母后跟小写字母。正向前瞻将寻找另一个以大写字母开头后跟小写字母的单词,但不会将其包含在匹配项中。

看这里:http://regexr.com?30ooo

【讨论】:

以上是关于用于在 java 中将 CamelCase 转换为 camel_case 的正则表达式的主要内容,如果未能解决你的问题,请参考以下文章

正则表达式在 Redshift 中将 CamelCase 转换为蛇形案例

如何在 R 中将 not.camel.case 转换为 CamelCase

在Ruby中将嵌套哈希键从CamelCase转换为snake_case

在 php __autoload() 中将 CamelCase 转换为 under_score_case

Java:JSON反序列化将小写转换为camelCase

将 Java 字符串从全部大写(由下划线分隔的单词)转换为 CamelCase(无单词分隔符)的最简单方法是啥?