如何将连字符分隔的标签名称转换为驼峰式

时间:2018-06-28 04:36:11

标签: java regex string

我有一个类似-的字符串

<phone-residence></phone-residence><marital-status>1</marital-status><phone-on-request></phone-on-request>

我要删除连字符(-),并将每个删除的连字符后面的单个字母字符大写。即从连字符分隔的单词转换为“ CamelCase”。

像-

<phoneResidence></phoneResidence><maritalStatus>1</maritalStatus><phoneOnRequest></phoneOnRequest>

该怎么做?

4 个答案:

答案 0 :(得分:4)

实际上,这非常简单。只需阅读输入字符串中的每个字符,然后使用boolean来决定是按原样添加,大写还是忽略字符():

public class Main {
    public static void main(String[] args) {
        String input = "<phone-residence></phone-residence><marital-status>1</marital-status><phone-on-request></phone-on-request>";
        StringBuilder output = new StringBuilder();
        boolean capitalizeNext = false;
        for (int i = 0; i < input.length(); i++) {
            char thisChar = input.charAt(i);
            if (thisChar == '-') {
                capitalizeNext = true;
            } else if (capitalizeNext) {
                output.append(String.valueOf(thisChar).toUpperCase());
                capitalizeNext = false;
            } else {
                output.append(thisChar);
                capitalizeNext = false;
            }
        }
        System.out.println(output.toString());
    }
}
  

输出:

<phoneResidence></phoneResidence><maritalStatus>1</maritalStatus><phoneOnRequest></phoneOnRequest>


带有其他注释的相同代码:

public class Main {
    public static void main(String[] args) {
        String input = "<phone-residence></phone-residence><marital-status>1</marital-status><phone-on-request></phone-on-request>";

        StringBuilder output = new StringBuilder();

        // This is used to determine if the next character should be capitalized
        boolean capitalizeNext = false;

        // Loop through each character of the input String
        for (int i = 0; i < input.length(); i++) {

            // Obtain the current character from the String
            char thisChar = input.charAt(i);

            if (thisChar == '-') {

                // If this character is a hyphen, set the capitalizeNext flag, but do NOT add this character to 
                // the output string (ignore it)
                capitalizeNext = true;

            } else if (capitalizeNext) {

                // The last character was a hyphen, so capitalize this character and add it to the output string
                output.append(String.valueOf(thisChar).toUpperCase());

                // Reset the boolean so we make a new determination on the next pass
                capitalizeNext = false;

            } else {

                // Just a regular character; add it to the output string as-is
                output.append(thisChar);

                // Reset the boolean so we make a new determination on the next pass
                capitalizeNext = false;

            }
        }

        // Just print the final output
        System.out.println(output.toString());
    }
}

答案 1 :(得分:4)

自从Java 8功能接口以来,String#replaceAll()就具有转换功能,可以“即时”修改匹配的子序列并构建最终输出。

首先,警告:正则表达式是出色的工具,功能强大,可解决特定类别的问题 。在应用正则表达式之前,您必须确定问题是否可以解决。通常,处理XML是正则表达式可解决的问题的对立面,除非在这种情况下,目标是将输入仅视为字符串而不是XML。 (但是请仔细阅读下面的警告)

这是杰米·扎温斯基(Jamie Zawinski)1997年的一句名言:

  

有些人遇到问题时会认为“我知道,我会使用正则表达式”。现在他们有两个问题。

解决方案

有了这些警告,这是您的问题代码:

    String input="<phone-residence></phone-residence><marital-status>1</marital-status><phone-on-request></phone-on-request>";
    Matcher m = Pattern.compile("-[a-zA-Z]").matcher(input);
    // Do all the replacements in one statement using the functional replaceAll()
    String result = m.replaceAll(s -> s.group().substring(1).toUpperCase());

说明

正则表达式匹配单个连字符,后跟任何单个字母字符(大写或小写)。 replaceAll()使用Matcher扫描输入。在每次匹配时,它都会调用lambda(具有单个apply()方法的匿名类的功能缩写),并传入包含匹配文本的String参数。然后,无论lambda返回什么,都将替换为replaceAll()方法构建的输出字符串,以代替匹配的字符串。

注意

上面给出的解决方案完全不了解XML的结构,它将更改任何-a组合(其中a代表任何字母)并仅用A(其中A代表大写字母),无论它出现在何处。

在您给出的示例中,此模式仅出现在标签名称中。但是,如果文件的其他部分包含(或可以包含)该模式,则这些实例也将被替换。如果该模式出现在文本数据中(即内部 不是,而是标签之间 )或作为属性值,则可能会出现问题。这种将正则表达式盲目地应用于整个文件的方法是一种链锯方法。如果确实需要,请使用电锯。

但是,如果发现电锯过于强大并且您的实际任务需要更多技巧,那么您将需要切换到可以处理所有细微问题的真实XML解析器(JDK包括一个很好的解析器)。它分别为您提供了各种语法位和片段,例如标记名,属性名,属性值,文本等,以便您可以明确决定哪些部分将受到影响。您仍将使用上面的replaceAll(),但仅将其应用于需要的部分。

几乎绝对不会使用正则表达式来处理XML,也不会解析包含嵌套或转义引号的字符串,也不会解析CSV或TSV文件。这些数据格式通常不适合使用正则表达式。

答案 2 :(得分:2)

如果您确定XML文件中元素的值中没有任何连字符,或者它们是否受更改影响都没有关系,则可以使用以下代码:

代码:

String input="<phone-residence></phone-residence><marital-status>1</marital-status><phone-on-request></phone-on-request>";
//this regex will match all letters preceded by a hyphen
Matcher m = Pattern.compile("-[a-zA-Z]").matcher(input);
//use a string builder to manipulate the intermediate strings that are constructed
StringBuilder sb = new StringBuilder();
int last = 0;

//for each match
while (m.find()) {
    //append the substring between the last match (or the beginning of the string to the beginning of the current match 
    sb.append(input.substring(last, m.start()));
    //change the case to uppercase of the match
    sb.append(m.group(0).toUpperCase());
    //set last to the end of the current match
    last = m.end();
}
//add the rest of the input string          
sb.append(input.substring(last));
//remove all the hyphens and print the string
System.out.println(sb.toString().replaceAll("-", ""));

输出:

<phoneResidence></phoneResidence><maritalStatus>1</maritalStatus><phoneOnRequest></phoneOnRequest>

改进:

如果XML元素的值中带有连字符,并且您希望它们受到此更改的影响,则可以使用以下代码(此简化版本仅在您的元素中没有属性(可以为属性添加逻辑),并且可以用于较小的XML树(您可能必须增加较大XML文档的堆栈大小,以避免出现stack overflow错误)

代码:

String input="<contact-root><phone-residence>abc-abc</phone-residence><marital-status>1</marital-status><phone-on-request><empty-node></empty-node></phone-on-request><empty-node/><not-really-empty-node>phone-on-request</not-really-empty-node></contact-root>";      
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(new StringReader(input)));          
StringBuilder strBuild = new StringBuilder();
xmlTrasversal(doc.getDocumentElement(),-1, strBuild);
System.out.println(input);
System.out.println();
System.out.println(strBuild.toString());

使用的功能:

  public static String capitalizeNext(String input){

        Matcher m = Pattern.compile("-[a-zA-Z]").matcher(input);
        StringBuilder sb = new StringBuilder();
        int last = 0;
        while (m.find()) {
            sb.append(input.substring(last, m.start()));
            sb.append(m.group(0).toUpperCase());
            last = m.end();
        }           
        sb.append(input.substring(last));
        return (sb.toString().replaceAll("-", ""));

  }

  public static void xmlTrasversal(Element e, int depth, StringBuilder strBuild)
  {
        ++depth;
        String spaces="  ";
        spaces=String.join("", Collections.nCopies(depth, spaces));
        if(!e.hasChildNodes())
            strBuild.append(spaces+"<"+capitalizeNext(e.getNodeName())+"/>"+System.getProperty("line.separator"));
        else if(e.getChildNodes().getLength()==1 && !(e.getChildNodes().item(0) instanceof Element))
        {
            strBuild.append(spaces+"<"+capitalizeNext(e.getNodeName())+">");
            strBuild.append(e.getTextContent());
        }
        else
        {
            strBuild.append(spaces+"<"+capitalizeNext(e.getNodeName())+">"+System.getProperty("line.separator"));
        }

        for (int i=0; i<e.getChildNodes().getLength();i++) 
        {
             if (e.getChildNodes().item(i) instanceof Element) {
                 xmlTrasversal((Element) e.getChildNodes().item(i), depth, strBuild);
            }
        }
        if(e.getChildNodes().getLength()==1 && !(e.getChildNodes().item(0) instanceof Element))
            strBuild.append("</"+capitalizeNext(e.getNodeName())+">"+System.getProperty("line.separator"));
        else if(e.hasChildNodes() && (e.getChildNodes().item(0) instanceof Element))
            strBuild.append(spaces+"</"+capitalizeNext(e.getNodeName())+">"+System.getProperty("line.separator"));

  }

输入字符串的输出:

<contactRoot>
  <phoneResidence>abc-abc</phoneResidence>
  <maritalStatus>1</maritalStatus>
  <phoneOnRequest>
    <emptyNode/>
  </phoneOnRequest>
  <emptyNode/>
  <notReallyEmptyNode>phone-on-request</notReallyEmptyNode>
</contactRoot>

答案 3 :(得分:0)

尝试一下:

    String str = "<phone-residence></phone-residence><marital-status>1</marital-status><phone-on-request></phone-on-request>";
    StringBuilder sb = new StringBuilder();
    StringTokenizer stk = new StringTokenizer(str,"-");
    while(stk.hasMoreTokens()){
        sb.append(WordUtils.capitalize(stk.nextToken()));
    }

    System.out.println(sb.toString());