首页 > 解决方案 > 反转单词而不改变大写或标点符号

问题描述

创建一个字符最少的程序,以反转字符串中的每个单词,同时保持单词的顺序,以及标点符号和大写字母,在它们的初始位置。

通过“单词的顺序”,我的意思是每个单词都被一个空格(“”)分隔,因此缩写等将被视为一个单词。宫缩中的撇号应该留在同一个地方。(“不要”=>“不”)。

(标点符号表示任何不是 az、AZ 或空格的字符*)。

Numbers were removed from this list due to the fact that you cannot have capital numbers. Numbers are now treated as punctuation.

例如,对于输入:

你好,我是一条鱼。

它应该输出:

Olleh,我是一个 hsif。

请注意,O 是第一个单词中的第一个字母,现在是大写字母,因为 H 之前在同一位置是大写字母。

逗号和句号也在同一个地方。

更多示例:

这个; 是一些文字!

会输出

希特; Si Emos Txet!

我试过这个:

 public static String reverseWord(String input)
    {
         
        String words[]=input.split(" ");
         StringBuilder result=new StringBuilder();
       
          for (String string : words) {
              String revStr = new StringBuilder(string).reverse().toString();
              result.append(revStr).append(" ");
          }
        return result.toString().trim();
        
    } 

标签: javastring

解决方案


这是一个符合您要求的建议。它可能看起来很长,但它只是注释和充气代码;每个人都喜欢评论。

public static String smartReverseWords(String input) {
    StringBuilder finalString = new StringBuilder();
    // Word accumulator, resetted after each "punctuation" (or anything different than a letter)
    StringBuilder wordAcc = new StringBuilder(); 
    int processedChars = 0;
    
    for(char c : input.toCharArray()) {
        // If not a whitespace nor the last character
        if(!Character.isWhitespace(c)) {  
            // Accumulate letters 
            wordAcc.append(c);   
            
            // Have I reached the last character? Then finalize now:
            if(processedChars == input.length()-1) {
                reverseWordAndAppend(wordAcc, finalString);
            }
        }        
        else {
            // Was a word accumulated?
            if(wordAcc.length() > 0) {
                reverseWordAndAppend(wordAcc, finalString);
            }
            // Append non-letter char to final string:
            finalString.append(c);
        }
        processedChars++;
    }
    return finalString.toString();
}

private static void reverseWordAndAppend(StringBuilder wordAcc, StringBuilder finalString) {
    // Then reverse it:
    smartReverse(wordAcc);  // a simple wordAcc.reverse() is not possible

    // Append word to final string:
    finalString.append(wordAcc.toString());
    
    // Reset accumulator 
    wordAcc.setLength(0);        
}

private static class Marker {
    Integer position;
    String character;
}

private static void smartReverse(StringBuilder wordAcc) {
    char[] arr = wordAcc.toString().toCharArray();
    wordAcc.setLength(0);  // clean it for now
    
    // Memorize positions of 'punctuation' + build array free of 'punctuation' in the same time:
    List<Marker> mappedPosOfNonLetters = new ArrayList<>();     // order matters
    List<Integer> mappedPosOfCapitals = new ArrayList<>();      // order matters
    
    for (int i = 0; i < arr.length; i++) {
        char c = arr[i];
        if(!Character.isLetter(c)) {
            Marker mark = new Marker();
            mark.position = i;
            mark.character = c+"";
            mappedPosOfNonLetters.add(mark);
        }
        else {
            if(Character.isUpperCase(c)) {
                mappedPosOfCapitals.add(i);
            }
            wordAcc.append(Character.toLowerCase(c));
        }
    }
    
    // Reverse cleansed word:
    wordAcc.reverse();

    // Reintroduce 'punctuation' at right place(s)
    for (Marker mark : mappedPosOfNonLetters) {
        wordAcc.insert(mark.position, mark.character);
    }
    // Restore capitals at right place(s)
    for (Integer idx : mappedPosOfCapitals) {
        wordAcc.setCharAt(idx,Character.toUpperCase(wordAcc.charAt(idx)));
    }    
}

编辑

我已经更新了代码以考虑您的所有要求。事实上,我们必须确保“标点符号”保持在原位(以及大写字母),但也要保持在一个单词之内,例如缩略语。

因此给定以下输入字符串:

"Hello, I am on StackOverflow. Don't tell anyone."

该代码产生以下输出:

"Olleh, I ma no WolfrEvokcats. Tno'd llet enoyna."

推荐阅读