'Using String.replace to replace a multi-line section of the string in Rust
I am trying to use Rust to go through and make changes to an HTML file. Basically, I find specific things in the code that I want replaced, then I replace it with something else using String.replace(stringToReplace, replacingString). This has been working well until I tried to replace a multi-line section of it. For example:
index.html
<div id="outer">
<h1>Some title</h1>
<p>Some text</p>
</div>
newIndex.html
<p>I have replaced the whole div</p>
No matter what I have tried, I cannot get the string to match for multiple lines. It just simply never replaces it. How do I go about matching on that multi-line part of the code. I thought about doing each line individually, but I obviously can't do that because replacing </div>
would not be good.
Below is the code I am using. I cannot make any changes to the original code to make it easier to match. In main.rs I am looping through Change.changes the even indices are the string to replace and the odd indices are the replacing text.
main.rs
use std::fs::File;
use std::io::prelude::*;
mod ejs;
mod js;
mod classes;
mod controllers;
mod change;
fn main() {
let ejs_files: Vec<change::Change> = ejs::change();
let js_files: Vec<change::Change> = js::change();
let class_files: Vec<change::Change> = classes::change();
let controller_files: Vec<change::Change> = controllers::change();
for i in 0..ejs_files.len() {
let mut contents = match read_file(&ejs_files[i].location) {
Ok(contents) => contents,
Err(e) => panic!(e)
};
let mut j = 0;
while j < ejs_files[i].changes.len() {
contents = contents.replace(ejs_files[i].changes[j], ejs_files[i].changes[j+1]);
j += 2;
}
match write_file(&ejs_files[i].location, contents) {
Err(e) => panic!(e),
_ => ()
};
}
for i in 0..js_files.len() {
let mut contents = match read_file(&js_files[i].location) {
Ok(contents) => contents,
Err(e) => panic!(e)
};
let mut j = 0;
while j < js_files[i].changes.len() {
contents = contents.replace(js_files[i].changes[j], js_files[i].changes[j+1]);
j += 2;
}
match write_file(&js_files[i].location, contents) {
Err(e) => panic!(e),
_ => ()
};
}
for i in 0..class_files.len() {
let mut contents = match read_file(&class_files[i].location) {
Ok(contents) => contents,
Err(e) => panic!(e)
};
let mut j = 0;
while j < class_files[i].changes.len() {
contents = contents.replace(class_files[i].changes[j], class_files[i].changes[j+1]);
j +=2;
}
match write_file(&class_files[i].location, contents) {
Err(e) => panic!(e),
_ => ()
};
}
for i in 0..controller_files.len() {
let mut contents = match read_file(&controller_files[i].location) {
Ok(contents) => contents,
Err(e) => panic!(e)
};
let mut j = 0;
while j < controller_files[i].changes.len() {
contents = contents.replace(controller_files[i].changes[j], controller_files[i].changes[j+1]);
j +=2;
}
match write_file(&controller_files[i].location, contents) {
Err(e) => panic!(e),
_ => ()
};
}
}
fn read_file(file: &str) -> std::io::Result<String> {
let mut file = File::open(file)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
fn write_file(file: &str, contents: String) -> std::io::Result<()> {
let mut file = File::create(file)?;
file.write(contents.as_bytes())?;
Ok(())
}
change.rs
pub struct Change<'a> {
pub location: String,
pub changes: Vec<&'a str>
}
js.rs (short example):
use crate::change::Change;
pub fn change<'a>() -> Vec<Change<'a>> {
let folder_location: &str = "../../javascript/InventoryManagement/";
let home_js = Change {
location: format!("{}{}", folder_location, "views/dashboardPage/js/strands/home.js"),
changes: vec![
"% vs last month", "% по сравнению с прошлым месяцем",
"REVENUE", "ДОХОД",
"\"DATE\"", "\"ДАТА\"",
"MOST POPULAR INGREDIENTS", "САМЫЕ ПОПУЛЯРНЫЕ ИНГРЕДИЕНТЫ",
"QUANTITY", "КОЛИЧЕСТВО"
]
};
In main.rs I am going through different files and replacing certain things. JS, HTML(EJS) and eventually CSS. Making the changes works well until I have to make a multi-line change. If I do something like this then it doesn't work.
js.rs (multi-line):
use crate::change::Change;
pub fn change<'a>() -> Vec<Change<'a>> {
let folder_location: &str = "../../javascript/InventoryManagement/";
let home_js = Change {
location: format!("{}{}", folder_location, "views/dashboardPage/js/strands/home.js"),
changes: vec![
"<div id='something'>
<p>My multi-line comment</p>
</div>",
"<p>Something else</p>"
]
};
vec![home_js]
}
If there is a better way to do this, then I would love to know as well. Or just a way to find and replace multi-line parts of the code. I am pretty new to Rust and this is the first project I have done with it.
Solution 1:[1]
You could use regex
crate and write a function. it replaces anything that matches the given text.
use regex::Regex;
fn replace(target: &str, replaceWith: &str, text: &str)-> Result<String, regex::Error>
{
let regex = Regex::new(target)?;
Ok(regex.replace_all(text, replaceWith).to_string())
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Yilmaz |