There is a text in the format:

I love the threat in the beginning of May, "When the spring of the first_Grom", as if frolic_and playing, rumbles in the sky_gold.

Should be:

I love the Thunderstorm in the Beginning of May, "When the spring of the first_Grom", as if firing and playing, rumbles in a nebeHeak.

Let me explain, you need to remove all underscores, except for those in quotes, everything should be intact. From the great presentation of the regular expression master (sercxjo), we were able to deal with the underscore ( "_(?=([^\"]*[^\\\\])(\"([^\"\\\\]|\\\\\\.)*\"[^\"]*)*$)" ), but now we need to write a regular record that raises the case of the letters after the underscore, but also does not touch the text in quotes.

  • 2
    And where is the expression that works without quotes? - Wiktor Stribiżew
  • "_ (? = ([^ \"] * [^ \\\])) (\ "([^ \" \\\] | \\\\.) * \ "[^ \"] *) * $ ) " - RattenGW
  • one
    The question of backfilling - is it worth it to be perverted with regulars, if it would be more convenient and readable to write an algorithm? Offhand, the decision does not come regular, and if you write - the devil will not figure it out later. - Goncharov Alexander
  • Alexander, I see it as: We pass through the replaceAll method - we change all lower case letters to the upper ones, after the underscore. And then go over the same method and delete all underscores. You just answer - is it possible to write a register-changing regular? - RattenGW
  • ReplaceAll () replaces all occurrences of a substring in a string with a new substring, in your case, the replacement substring is not one, but several, and this method is not applicable. - Aleksei Chibisov

2 answers 2

You need a class Matcher , code like this:

  public static void main(String[] args) throws InterruptedException { String regex = "_[а-яА-ЯёЁъЪ](?=([^\"]*[^\\\\])(\"([^\"\\\\]|\\\\.)*\"[^\"]*)*$)"; String str = "Люблю_грозу в_начале_Мая, \"Когда весенний_первый_Гром\", как бы Резвяся_и Играя, Грохочет в_небе_голубом."; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(str); while (matcher.find()){ String s = str.substring(matcher.end()-1,matcher.end()).toUpperCase(); str = str.replace(str.substring(matcher.start(), matcher.end()),s); matcher.reset(str); } System.out.println(str); } 

The only thing I forgot is how to get immediate matches on the regular schedule, so the code can be improved.

  • Thank you, with your permission, I dig through your code) I read from a file and wrote the result to a file, and between them I wrote this - String everything = read ("C: \\ a.java"). ReplaceAll ("_ (? = ( [^ \ "] * [^ \\\]) (\" ([^ \ "\\\] | \\\\.) * \" [^ \ "] *) * $)", "") ; - RattenGW
  • Alexey, the code is good, working. Somewhere I misfired, but I could not catch it) Thank you! - RattenGW
  • In general, in Java, constructions of the type ([^\"\\\\]|\\\\.)* Must be deployed (" unroll-the-loop "), otherwise stack lengths may jump out when processing long lines. matcher.group(0) - Wiktor Stribiżew

I don’t know how to solve your problem using only tools for working with regular expressions, but you can try to write an analogue of the Matcher.replaceAll method like this:

  String myReplaceAll(String pattern, String text, String replacement) { Pattern p = Pattern.compile(pattern); Matcher m = p.matcher(text); StringBuffer sb = new StringBuffer(); for (int length = 0; m.find(); length = sb.length()) { m.appendReplacement(sb, replacement); if(length > 0) { sb.setCharAt(length, Character.toUpperCase(sb.charAt(length))); } } m.appendTail(sb); return sb.toString(); } 

You can do the same without explicitly using classes for working with regular expressions:

 String myReplaceAll(String symbol, String text, String replacement) { StringBuilder sb = new StringBuilder(); for (String textChunk : text.split(symbol)) { int prevLength = sb.length(); sb.append(textChunk); if(prevLength > 0) sb.setCharAt(prevLength, Character.toUpperCase(sb.charAt(prevLength))); } return sb.toString(); } 

Or, as they wrote in the comments, to write an implementation without regulars, this is especially true if you are not looking for patterns in the string, but for individual characters. For starters, I can offer something like this:

 String myReplaceAll(char patternSymbol, char startSkippingSymbol, char stopSkippingSymbol, String text, String replacement) { char[] chars = text.toCharArray(); char[] resultString = new char[chars.length]; boolean upperNext = false, stopSearching = false; for (int index = 0, newIndex = 0; index < chars.length; index++) { char symbol = chars[index]; stopSearching = startSkippingSymbol == symbol ? (stopSearching ? false : true) : stopSearching; if(!stopSearching) { if (upperNext) { symbol = Character.toUpperCase(symbol); upperNext = false; } if (patternSymbol == symbol) { upperNext = true; continue; } } resultString[newIndex++]=symbol; } return new String(resultString); } 
  • one
    Valentin thank you! Before your decision, I firmly believed in the regulars, it turns out to be nothing! - RattenGW