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");
}
}
non-specific-targeting-replacement tag
containing anadjacent-replacement word
(hard to say in one sentence, see my updated answer for better explanation).