-1
String value="==Hello==";

For the above string, I have to replace the "==" tags as <Heading>Hello</Heading>. I have tried doing it like this:

value = value.replaceAll("(?s)\\=\\=.","<heading>");
value = value.replaceAll(".\\=\\=(?s)","</heading>");

However, my original dataset is huge, with lots of strings like this to be replaced. Can the above be performed in a single statement, giving preference to performance?

The regex should not affect strings of form, ===<value>===, where value is any string of characters[a-z,A-Z].

darth
  • 169
  • 1
  • 16
  • 1
    `replaceAll("===([^=]+)===", "$1")` – Andreas Jun 11 '17 at 20:15
  • @darth can input look like `==foo=bar==`? If yes what should be result? Or `==a==b==c==`? – Pshemo Jun 11 '17 at 20:22
  • What does "solution't" mean? – Andreas Jun 11 '17 at 20:24
  • The input will be of the form, "====", or ====== – darth Jun 11 '17 at 20:26
  • To clarify your question please use [edit] option. Don't make people search for crucial info in comments. Also what exactly `` represent? Can it for instance contain another nested `====`? If yes how should it be handled? – Pshemo Jun 11 '17 at 20:27
  • No, it can only contain strings,[a-z,A-Z] – darth Jun 11 '17 at 20:31
  • So for now it looks like you want to replace `==value==` but not `===value===`. In other words you want to replace two continuous equation marks but not three. In that case you may be looking for `value = value.replaceAll("(?<!=)==([a-zA-Z])==(?!=)","$1");` `(?<!subexpression)` ensures that `subexpression` (here `=`) doesn't appear *before* match, similarly `(?!subexpression)` that `subexpression` (here `=`) doesn't appear *after* match. For more info read about "regex lookaround". – Pshemo Jun 11 '17 at 20:36
  • Anyway since your input also contains `======` something tells me you will want to also replace these but with different tags. If that is true then your question is example of [X/Y problem](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) where for real problem there may be better solution than the problem you described. – Pshemo Jun 11 '17 at 20:39
  • If I use replaceAll("===([^=]+)===", "$1"); and then replaceAll("==([^=]+)==", "$1"), the problem is solved. I just need to solve bigger regex (===), before trying to solve for (==). Thank you for your help. Do you think I should delete this question due to bad quality? – darth Jun 11 '17 at 20:43
  • I am not sure. In your solution you need to iterate over string twice, once searching for `===` then second for `==`. You could do it in one iteration with little help of `Matcher#appendReplacement` and `Matcher#appendTail`. Also I am saying this because I am making some assumptions about how your input is formatted so solution which I am thinking about may not work if there is something I didn't know about input. Anyway give me a minute, I will post my idea as answer and you can decide if it was what you ware looking for. – Pshemo Jun 11 '17 at 20:50

2 Answers2

0

Try this:

public static void main(final String[] args) {
        String value = "===Hello===";
        value = value.replaceAll("===([^=]+)===", "<Heading>$1</Heading>");
        System.out.println(value);
    }
kk.
  • 3,747
  • 12
  • 36
  • 67
0

To avoid iterating over string many times to first replace ===abc=== and then ==def== we can iterate over it once and thanks to Matehr#appendReplacement and Matcher#appendTail dynamically decide how to replace found match (based on amount of =).

Regex which can search find both described cases can look like: (={2,3})([a-z]+)\1 but to make it more usable lets use named groups (?<name>subregex) and also instead of [a-z] use more general [^=]+.

This will give us

Pattern p = Pattern.compile("(?<eqAmount>={2,3})(?<value>[^=]*)\\k<eqAmount>");

Group named eqAmount will hold == or ===. \\k<eqAmount> is backreference to that group, which means regex expects to find it also == or === depending on what eqAmount already holds.

Now we need some mapping between == or === and replacements. To hold such mapping we can use

Map<String,String> replacements = new HashMap<>();
replacements.put("===", "<subheading>${value}</subheading>");
replacements.put("==", "<heading>${value}</heading>");

${value} is reference to capturing group named value - here (?<value>[^=]*) so it will hold text between both == or ===.

Now lets see how it works:

String input = "===foo=== ==bar== ==baz== ===bam===";

Map<String, String> replacements = new HashMap<>();
replacements.put("===", "<subheading>${value}</subheading>");
replacements.put("==", "<heading>${value}</heading>");

Pattern p = Pattern.compile("(?<eqAmount>={2,3})(?<value>[^=]*)\\k<eqAmount>");

StringBuffer sb = new StringBuffer();
Matcher m = p.matcher(input);
while (m.find()) {
    m.appendReplacement(sb, replacements.get(m.group("eqAmount")));
}
m.appendTail(sb);

String result = sb.toString();
System.out.println(result);

Output: <subheading>foo</subheading> <heading>bar</heading> <heading>baz</heading> <subheading>bam</subheading>

Pshemo
  • 122,468
  • 25
  • 185
  • 269