0

Situation

Here is the Regex & Substitution I used for Regex replace in Dreamweaver::

(( and )|( that )|( include )|( includes )|( including ))
$1<br/>\n

image: settings for Regex Replace in Dreamweaver

2.

After I Replace All in current document. I found few errors.

eg::

create new Flux and Mono instances

is being replaced into (wrong one)

create new Flux that <br/>
Mono instances

actual image

instead of (correct one)

create new Flux and <br/>
Mono instances

( regex101 visualization => https://regex101.com/r/hJTqFg/1 )

Question

Why is this happening?

How can I avoid this? (A safer approach for Replacement?)

Have this happened to you before?

note:

  • There are a lot of replacements happened in this document -- around 300+ -- this document is large.
  • When the replacement process is going. I can see Dreamweaver scroll through the source code quickly.

    Instead of just instantly replace all replacements (which is different from what other text editing software would do).

    Is this normal?

    This makes me suspect that the problem is due to the replacement speed -- the lag made Dreamweaver somehow replace the text into the previous replaced one ...? -- (but idk, idk how internally Dreamweaver is implemented..)

  • (There are only few errors -- but still, this should not happen.)

  • (The replacement is specifically for html tag <p> (I dont think this is the problem))

  • (More precisely,

    the original text is create new <code class="literal">Flux</code> and <code class="literal">Mono</code> instances

    instead of just create new Flux and Mono instances

    (for the sake of readability, I simplified it, but it does not matter).)

  • Using Dreamweaver Version 2021

  • Replacement is on a .xhtml file

  • Its not just get replaced into other String (thats in the regex pattern) due to the | in regex pattern.

    There are also mistakes where some characters just get disappeared... (though, this is even more rare)

    eg: blockhound becomes lockhound; 1.0.1.RELEASE becomes .0.1.RELEASE;

    (I didnt just do 1 regex replace pattern, there are also other patterns that I applied to this document;

    though, these 2 eg above, certainly should not be matched in any regex patterns that I used for this document...)

  • I did another regex replace test, by using the option in (Documents in) Folder ..., not Current Document

    -- so, the effect of scrolling will not present (& this seems process faster)

    Though, even with this, there are still Errors.

    -- so, it seems like the occurence of Error has nothing to do with the scrolling in regex replace in Dreamweaver.



Below is Simplified example of above (if above contains redundant information)

In short:

0 . you have some text

<p>AA and BB</p>

1 . if you use a regex pattern contains an or syntax, |, eg:

(( and )|( that ))

2 . and your replacement contains a capture group $1, eg:

$1foobar

3 . and you perform an regex replace all in Dreamweaver specific to a tag, say: <p> (I call it specific-targeting-replacement tag)

4 .

  • and there is a tag (a tag that is not of type <p>), above <p>, say: <li> (I call it non-specific-targeting-replacement tag)

  • and <li> contains the word that (the that word presents in the regex pattern (with or syntax) that is adjacent to and),

    • (I call that word that as adjacent-replacement word,

    • I call the word and as to-be-replaced word)

<ul>
  <li>xxxx that xxxx</li>
</ul>

5 . then the text in tag <p> below that tag <li>, would be replaced with the wrong String (the adjacent-replacement word). eg:

it should be replaced into (correct)

<p>AA and foobarBB</p>

but it may be replaced into (wrong)

<p>AA that foobarBB</p>

img: file & procedure to create this error

the testing file:

<!DOCTYPE html>
<html>
<body>
<p>AA and BB</p>
<p>AA and BB</p>
<ul>
  <li>xxxx that xxxx</li>
</ul>
<p>AA and BB</p>
<p>AA and BB</p>
</body>
</html>
6
  • Ask Dreamweaver developpers, this is a bug.
    – Toto
    Commented Jun 10, 2022 at 9:57
  • Sure. I'm also curious did this happened to other people.
    – Nor.Z
    Commented Jun 10, 2022 at 15:27
  • Please, post a minimal example that has this behaviour.
    – Toto
    Commented Jun 12, 2022 at 8:04
  • @Toto ++ Sorry, I should have done that in the first time. ++ But I wasnt 100% sure what specifically cause that behaviour. (also I didnt know how complex this ex would grow to.) ++ So, I put out whatever I suspected that would cause this. ++ Later, I added a simplified example, base on what I knew. ++ Now, I tried and tested a lot of files -- to try to reduce the text in the testing file, while being able to reproduce the behaviour. And I finally simplied it enough to get to that missing piece
    – Nor.Z
    Commented Jun 17, 2022 at 8:23
  • [^ continue] ++ -- its cause by the non-specific-targeting-replacement tag containing an adjacent-replacement word (hard to say in one sentence, see my updated answer for better explanation).
    – Nor.Z
    Commented Jun 17, 2022 at 8:23

2 Answers 2

0

Here is a solution with Notepad++:

  • Ctrl+H
  • Find what: (?:<p>|\G)(?:(?!</p>).)*?\b(?:and|that|includes?|including)\b\K(?=.*?</p>)
  • Replace with: foobar
  • CHECK Wrap around
  • CHECK Regular expression
  • CHECK . matches newline
  • Replace all

Explanation:

(?:         # non capture group
    <p>         # openning tag
  |           # OR
    \G          # restart from last match position
)           # end group
        # Tempered Greedy Token
(?:         # non capture group
    (?!</p>)    # negative lookahead, make sure we haven't </p> just after
    .           # any character
)*?         # end group, may appear 0 or more times, not greedy
\b          # word boundary
(?:         # non capture   group
    and         # literally
  |           # OR
    that        # literally
  |           # OR
    includes?   # literally include OR includes
  |           # OR
    including   # literally
)           # end group
\b          # word boundary
\K          # reset operator, forget all we have seen until this position
(?=         # positive lookahead, make sure we have after:
    .*?         # 0 or more any character, noot greedy
    </p>        # closing tag
)           # end lookahead

Screenshot (before):

enter image description here

Screenshot (after):

enter image description here

3
  • ++ Amazing. ++ I have been searching for "how to regex replace content inside a specific html tag" for past few months. ++ The online answers are not specific to my case -- the question are either asking for: ++ *. only select the content but not match and replace inside the content; ++ *. replace only the tag; ++ *. use javascript; ++ *. dont use regex but a software for that (this is part of why I end up using Dreamweaver); ++ *. etc
    – Nor.Z
    Commented Jun 26, 2022 at 14:29
  • [^ continue] ++ Not sure why no one ask this before. (I think this is very useful.) ++ But now, after seeing this one-line clean regex provided in your answer. I think that is the way.
    – Nor.Z
    Commented Jun 26, 2022 at 14:29
  • @Nor.Z: You're welcome, glad it helps.
    – Toto
    Commented Jun 26, 2022 at 14:47
0

This is a bug. And there is no good solution for this in Dreamweaver for now. But there are workarounds.

Solution1 (workaround, very limited)

When using Dreamweaver. Do not use | (or) syntax & grouping syntax in your Regex pattern.

You need to replace them one by one. (this is a huge limitation on Regex)

  • (Though, there seems to be a way to batch process the replacement queries => link.)

Solution2 (recommended)

Use Calibre & Python function for replacement.

eg::

import re

# // finds and replaces the content inside tag <p> -- by `re.sub`
def replace(match, number, file_name, metadata, dictionaries, data, functions, *args, **kwargs):

    # // use the following Regex for finding in Calibre
    # (?P<tag_opening><p(|\s+[^>]*)>)(?P<content_inside_tag>.*?)(?P<tag_closing><\/p\s*>)
    m_p1 = match.group("tag_opening")
    m_main = match.group("content_inside_tag")
    m_p2 = match.group("tag_closing")

    m_main_re = m_main
    
    m_main_re = re.sub("(( and )|( that ))", "\\g<0><br>\n", m_main_re)

    # print(m_main_re)
    # return match.group(0)
    return m_p1 + m_main_re + m_p2

Solution3 (recommended)

same as Solution2, but with Java code.

package com.ex.main;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
@to_use: 
1. put the files that need to be regex replaced in `input folder` 
2. 
change the regex pattern in 
regexReplaceFileContent()
regexReplaceFileContent_innerMatch()
3. run 
4. get output filed from `output folder`
*/
public class RegexReplaceFile {

  //################################################################################################

  // loop & read the files in input folder & invoke regex replace for each file & output the replaced file to output folder
  // (files in input folder will not be modified)
  public static void regexReplaceAndReadWriteFilesInFolder(String path_InputFolder, String path_OutputFolder) {
    File dir_InputFolder = new File(path_InputFolder);
    File[] arr_file_InInputFolder = dir_InputFolder.listFiles();
    if (arr_file_InInputFolder.length == 0) {
      System.out.println("Folder is empty.");
      return;
    }
    for (File file_curr : arr_file_InInputFolder) {
      if (file_curr.isDirectory()) {
        System.out.println("Directory: " + file_curr.getAbsolutePath());
        // showFiles(file_curr.listFiles()); // recursion (if need to loop inside sub folders)
      } else {
        String path_InputFile = file_curr.getAbsolutePath();
        String path_OutputFile = path_OutputFolder + "/" + file_curr.getName();
        System.out.println("Input  File: " + path_InputFile);
        System.out.println("Output File: " + path_OutputFile);
        // do the regex replace for each file
        regexReplaceAndReadWriteFile(path_InputFile, path_OutputFile);
      }
    }
  }

  // ^^ do the regex replace for each file
  public static void regexReplaceAndReadWriteFile(String path_InputFile, String path_OutputFile) {
    // >> read content from input file
    StringBuilder contentBuilder = new StringBuilder();
    try {
      BufferedReader in = new BufferedReader(new FileReader(path_InputFile));
      String str;
      while ((str = in.readLine()) != null) {
        contentBuilder.append(str);
        contentBuilder.append("\n");
      }
      in.close();
    } catch (IOException e) {
      e.printStackTrace();
    }
    String content = contentBuilder.toString();
    //    System.out.println(content);

    // >> regex replace
    String content_re = regexReplaceContent_SpecificToATag(content);

    // >> write content to output file
    byte[] byte_Content = content_re.getBytes(StandardCharsets.UTF_8);
    Path file = Paths.get(path_OutputFile);
    try {
      Files.write(file, byte_Content);
    } catch (IOException e) {
      e.printStackTrace();
    }

  }

  //##########################################

  // ## loop replace with `StringBuilder.append & inner replace` 
  public static String regexReplaceContent_SpecificToATag(String content, boolean det_OmitSyso) {
    // >> find content specific to tag <p> 
    final String regexNamedGroup_tagOpening = "tagOpening";
    final String regexNamedGroup_contentInsideTag = "contentInsideTag";
    final String regexNamedGroup_tagClosing = "tagClosing";

    String content_SearchOn = content;
    String str_RegexPattern = "(?s)(?<tagOpening><p(|\s+[^>]*)>)(?<contentInsideTag>.*?)(?<tagClosing></p\s*>)"; // @to_use-param;
    Pattern pattern = Pattern.compile(str_RegexPattern);
    Matcher matcher = pattern.matcher(content_SearchOn);

    // >> for the content in each (found) paragraph <p>, do an replace
    StringBuilder sb_ContentSearchOn = new StringBuilder(content_SearchOn);
    StringBuilder content_Replaced = new StringBuilder();
    int ind_MatchGroupEnd_prev = 0;
    int ind_MatchGroupEnd_curr;
    int ind_MatchGroupStart_curr;
    while (matcher.find()) {
      // 
      ind_MatchGroupStart_curr = matcher.start(regexNamedGroup_contentInsideTag);
      ind_MatchGroupEnd_curr = matcher.end(regexNamedGroup_contentInsideTag);

      String content_BeforeMatchGroup = sb_ContentSearchOn.substring(ind_MatchGroupEnd_prev, ind_MatchGroupStart_curr); // prev end to curr start, not start to end

      content_Replaced.append(content_BeforeMatchGroup);

      // ^^ for the content in each (found) paragraph <p>, do an replace -- [inner match]
      String content_SearchOn_innerMatch__TheMatchGroup = matcher.group(regexNamedGroup_contentInsideTag);
      String content_Replaced_innerMatch = regexReplaceContent_SpecificToATag_innerMatch(content_SearchOn_innerMatch__TheMatchGroup);

      content_Replaced.append(content_Replaced_innerMatch);

      // 
      ind_MatchGroupEnd_prev = ind_MatchGroupEnd_curr;
    }

    // append the content after the last match group
    String content_AfterLastMatchGroup = sb_ContentSearchOn.substring(ind_MatchGroupEnd_prev, sb_ContentSearchOn.length());
    content_Replaced.append(content_AfterLastMatchGroup);

    // >>
    if (det_OmitSyso) {
      System.out.println(content_Replaced.substring(0, 300) + "\n[... omitted]\n");
    } else {
      System.out.println(content_Replaced);
    }
    return content_Replaced.toString();
  }

  public static String regexReplaceContent_SpecificToATag(String content) {
    boolean det_OmitSyso = true;
    return regexReplaceContent_SpecificToATag(content, det_OmitSyso); // 
  }

  // ^^ for the content in each (found) paragraph <p>, do an replace -- [inner match]
  private static String regexReplaceContent_SpecificToATag_innerMatch(String content_SearchOn_innerMatch__TheMatchGroup) {
    String str_RegexPattern_innerMatch;
    String str_Substitution_innerMatch;
    String content_Replaced_innerMatch = content_SearchOn_innerMatch__TheMatchGroup;

    // 
    //    str_RegexPattern_innerMatch = "( and then )";
    //    str_Substitution_innerMatch = " and then <br>\n";
    //    content_Replaced_innerMatch = content_Replaced_innerMatch.replaceAll(str_RegexPattern_innerMatch, str_Substitution_innerMatch);
    //
    str_RegexPattern_innerMatch = "(( and )|( that ))";
    str_Substitution_innerMatch = "$0<br>\n";
    content_Replaced_innerMatch = content_Replaced_innerMatch.replaceAll(str_RegexPattern_innerMatch, str_Substitution_innerMatch);
    //
    //    str_RegexPattern_innerMatch = "((\\. )|(, ))";
    //    str_Substitution_innerMatch = "$1<br>\n";
    //    content_Replaced_innerMatch = content_Replaced_innerMatch.replaceAll(str_RegexPattern_innerMatch, str_Substitution_innerMatch);
    //
    //    str_RegexPattern_innerMatch = "( by )";
    //    str_Substitution_innerMatch = " <br>\n++ by ";
    //    content_Replaced_innerMatch = content_Replaced_innerMatch.replaceAll(str_RegexPattern_innerMatch, str_Substitution_innerMatch);

    return content_Replaced_innerMatch;
  }

  //################################################################################################

  static final String content_TESTING = "    <p>These days if you are an android developer, you might hear some hype about RxJava. \n"
                                        + "RxJava is library which can help you get rid of all you complex write-only code that deals with asynchronous events. Once you start using it in your project – you will use it everywhere.</p>\n"
                                        + "\n"
                                        + "<p>The main pitfall here is steep learning curve. If you have never used RxJava before, it will be hard or confusing to take full advantage of it for the first time. The whole way you think about writing code is a little different.\n"
                                        + "Such learning curve creates problems for massive RxJava adoption in most projects.</p>\n"
                                        + "\n"
                                        + "<p>Of course there are a lot of tutorials and code examples around that explain how to use RxJava. \n"
                                        + "Developer interested in learning and using RxJava can first visit  the official <a href=\"https://github.com/ReactiveX/RxJava/wiki\">Wiki</a> that contains great explanation of what Observable is, how it’s related to Iterable and Future. Another useful resource is <a href=\"https://github.com/ReactiveX/RxJava/wiki/How-To-Use-RxJava\">How To Use RxJava</a> page which shows code examples of how to emit items and <code class=\"highlighter-rouge\">println</code> them.</p>\n"
                                        + "\n"
                                        + "<p>But what one really wants to know, is what problem RxJava will solve and how it will help organize async code without actually learning what Observable is.</p>\n"
                                        + "\n"
                                        + "<p>My goal here is to show some “prequel” to read before the official documentation in order to better understand the problems that RxJava tries to solve.\n"
                                        + "This article is positioned as a small walk-through on how to reorganize messy Async code by ourselfs to see how we can implement basic principles of RxJava without actually using RxJava.</p>\n"
                                        + "\n"
                                        + "<p>So If you are still curious let’s get started!</p>\n"
                                        + "\n"
                                        + "<h2 id=\"cat-app\">Cat App</h2>\n"
                                        + "<p>So let’s create a <em>real world</em> example. So we know that cats are the engine of technology progress, so let’s build \n"
                                        + "a typical app for downloading cat pictures.</p>\n"
                                        + "\n"
                                        + "<h4 id=\"so-here-is-the-task\">So here is the task:</h4>\n"
                                        + "<blockquote>\n"
                                        + "  <p>We have a webservice that provides api to search the whole internet for\n"
                                        + "images of cats by given query. Every image will contain cuteness\n"
                                        + "parameter - integer value that describes how cute is that picture. Our\n"
                                        + "task will be download a list of cats, choose the most cutest, and save\n"
                                        + "it to local storage.</p>\n"
                                        + "</blockquote>\n"
                                        + "\n"
                                        + "<p>We will focus only on downloading, processing and saving cats data.</p>\n"
                                        + "\n"
                                        + "<p>So let’s start:</p>\n"
                                        + "";

  public static void main(String[] args) throws Exception {
    // >> @to_use @M2 direclty input text
    boolean det_OmitSyso = false;
    regexReplaceContent_SpecificToATag(content_TESTING, det_OmitSyso);

    //    // >> @to_use @M1 input text from folder
    //    regexReplaceAndReadWriteFilesInFolder("G:/wsp/eclipse/RegexReplaceFile_AT_tool_AT_NT/src/main/resources/input__RegexReplace",
    //                                          "G:/wsp/eclipse/RegexReplaceFile_AT_tool_AT_NT/src/main/resources/output_RegexReplace");

  }

}

3
  • Why not using Notepad++ or SublimeText both are working fine with your regex? You can simplify it a bit and remove the useless groups that slowdown the process: ( and | that | includes? | including )
    – Toto
    Commented Jun 25, 2022 at 9:16
  • @Toto Because Notepad++ cannot regex replace the content specific to (inside) a tag. (or, does it have such functionality?)
    – Nor.Z
    Commented Jun 26, 2022 at 11:30
  • See my answer below.
    – Toto
    Commented Jun 26, 2022 at 12:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .