【问题标题】:Regex for converting CamelCase to camel_case in java用于在 java 中将 CamelCase 转换为 camel_case 的正则表达式
【发布时间】: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
*/

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

【问题讨论】:

标签: java regex string


【解决方案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】:

        看到这个questionCaseFormat 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("(.)(\\p{Upper})", "$1_$2").toLowerCase();
            

            【讨论】:

            • 如果我的字符串包含一个数字怎么办 - mode3 以 mode3 结尾,而我想要 mode_3。
            • 它不会像 MyUUID 这样将骆驼大小写正确地转换为下划线,我得到了 my_uu_id
            • @Mike/@User3301 试试这个String replaceAll = key.replaceAll("(.)(\\p{Upper}+|\\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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-03-11
              • 2017-12-15
              相关资源
              最近更新 更多