![](/img/trans.png)
[英]How to convert Camel Case to Lower Hyphen in Java when there are contiguous capitals
[英]How to convert hyphen-delimited tag names to camel case
我有一个字符串 -
<phone-residence></phone-residence><marital-status>1</marital-status><phone-on-request></phone-on-request>
我想在每个删除的连字符后删除连字符( -
)和大写单字母字符。 即从连字符分隔的单词转换为“CamelCase”。
喜欢 -
<phoneResidence></phoneResidence><maritalStatus>1</maritalStatus><phoneOnRequest></phoneOnRequest>
这个怎么做?
实际上,这非常简单。 只需读取输入字符串的每个字符,并使用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()); } }
由于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文件。 这些数据格式通常不适合使用正则表达式。
如果您确定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>
尝试这个:
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());
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.