Как преобразовать имена тегов, разделенных дефисом, в регистр верблюдов - PullRequest
0 голосов
/ 28 июня 2018

У меня есть строка типа -

<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 голосов
/ 28 июня 2018

Попробуйте:

    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());
0 голосов
/ 28 июня 2018

Это очень просто, на самом деле. Просто прочитайте каждый символ входной строки и используйте 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());
    }
}
0 голосов
/ 28 июня 2018

Начиная с функциональных интерфейсов Java 8, String#replaceAll() принимает функцию преобразования для изменения согласованных подпоследовательностей "на лету" и построения окончательного результата.

Во-первых, предупреждение: регулярные выражения являются фантастическими, невероятно мощными инструментами для определенного класса проблем . Перед применением регулярных выражений вы должны определить, поддается ли проблема. Обычно обработка XML является противоположностью проблемы, поддающейся регулярному выражению, за исключением того случая, когда целью является обработка ввода как простой строки, а не как XML. (Однако внимательно прочитайте предостережение ниже)

Вот известная цитата Джейми Завински в 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. При каждом совпадении он вызывает лямбду (функциональное сокращение для анонимного класса с единственным методом apply()), передающую аргумент String, содержащий сопоставленный текст. Все, что возвращает лямбда, затем подставляется в выходную строку, которая строится методом replaceAll(), вместо соответствующей строки.

Протест

Приведенное выше решение полностью закрывает структуру XML, оно изменит любую комбинацию -a (где a обозначает любую букву) и заменит ее просто A (где A обозначает прописная буква), независимо от того, где он появляется.

В приведенном вами примере этот шаблон встречается только в именах тегов. Однако, если существуют другие части файла, которые содержат (или могут содержать) этот шаблон, эти экземпляры также будут заменены. Это может быть проблемой, если этот шаблон встречается в текстовых данных (то есть вещи не внутри, но между тегами ) или в качестве значения атрибута. Этот метод применения регулярных выражений ко всему файлу вслепую является своего рода подходом бензопилы. Если вам действительно нужна бензопила, используйте ее.

Однако, если окажется, что бензопила слишком мощная, а ваша реальная задача требует более изощренной работы, вам потребуется переключиться на настоящий XML-парсер (JDK включает в себя хороший), который может обрабатывать все тонкости. Он предоставляет вам различные синтаксические фрагменты, такие как имя тега, имена атрибутов, значения атрибутов, текст и т. Д. По отдельности, так что вы можете явно решить, какие части должны быть затронуты. Вы все еще используете replaceAll() выше, но применяете его только к тем частям, где это было необходимо.

Почти как правило, вы АБСОЛЮТНО НЕ будете использовать регулярные выражения для обработки XML, разбирать строки, содержащие вложенные или экранированные кавычки, или разбирать файлы CSV или TSV. Эти форматы данных обычно не подходят для использования регулярных выражений.

0 голосов
/ 28 июня 2018

Если вы уверены, что значения элементов вашего 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...