Expanding on the excellent answer from Mark Moretto:
In Visual Studio 2019, this worked beautifully across my entire C++ codebase:
Replace this:
(.*print[(])(".*?")(.*[)];)
With this:
$1FMT_STRING($2)$3
Then repeat with this to handle fmt::format
:
(.*format[(])(".*?")(.*[)];)
For the global Search'n'Replace, ensure that RegEx
icon which is .*
is switched on.
I used .NET Regex Tester to form the expression.
It correctly fixed up 500 of 505 instances in about 5 seconds, but it it did trip up on this sort of thing which I fixed manually:
// Required manual fix (shift rogue bracket away from end).
auto y = format("Test=\"{}\""), 42);
Explanation (Optional)
I have always found RegEx expressions to be horribly complicated, but working through this example somehow made a lightbulb switch on in my head.
(.*print[(])
matches anything from the start of the line to the opening print(
and replaces with $1
.
(".*?")
matches from the opening to closing quote, and replaces with $2
.
(.*[)];)
matches everything to the closing );
, and replaces with $3
.
$1FMT_STRING($2)$3
inserts FMT_STRING()
in the right place.
Notes:
- On point 1:
- Note the use of
[(]
to indicate a literal (
.
- Note the use of
.*
. This is a wildcard where .
means any character and *
means any number of repetitions.
- It will also match on
fmt::print(
. Needs a different RegEx to handle format(
and fmt::format(
(see above).
- On point 2:
- Note the use of
?
to indicate that it should stop on the very first closing quote it sees (i.e. a "non-greedy match").
Appendix A: Test Cases (Optional)
Paste the Input Tests Cases
below into .NET Regex Tester for syntax highlighting and easier editing of the expression to modify it slightly.
Input test cases:
// Test non-namespace match.
print("Hello, world!");
print("Test: {}", 42);
print("Test: {}: {}", 42, "A");
print("Test: {:0}: {} : {}", 42, "A", myVariable);
print("{}, {}, {}", 42, "A", "B");
print("Hello, world!");
print("Test: {}", 42);
print("Test: {}: {}", 42, "A");
print("Test: {:0}: {} : {}", 42, "A", myVariable);
print("{}, {}, {}", 42, "A", "B");
// Test namespace match.
fmt::print("Hello, world!");
fmt::print("Test: {}", 42);
fmt::print("Test: {}: {}", 42, "A");
fmt::print("Test: {:0}: {} : {}", 42, "A", myVariable);
fmt::print("{}, {}, {}", 42, "A", "B");
fmt::print("Hello, world!");
fmt::print("Test: {}", 42);
fmt::print("Test: {}: {}", 42, "A");
fmt::print("Test: {:0}: {} : {}", 42, "A", myVariable);
fmt::print("{}, {}, {}", 42, "A", "B");
// Test compatibility with existing (should be no change).
fmt::print(FMT_STRING("Hello, world!"));
fmt::print(FMT_STRING("Test: {}"), 42);
fmt::print(FMT_STRING("Test: {}: {}"), 42, "A");
fmt::print(FMT_STRING("Test: {:0}: {} : {}"), 42, "A", myVariable);
fmt::print(FMT_STRING("{}, {}, {}"), 42, "A", "B");
fmt::print("Hello, world!");
fmt::print(FMT_STRING("Test: {}"), 42);
fmt::print(FMT_STRING("Test: {}: {}"), 42, "A");
fmt::print(FMT_STRING("Test: {:0}: {} : {}"), 42, "A", myVariable);
fmt::print(FMT_STRING("{}, {}, {}"), 42, "A", "B");
Output of test cases (all correct):
// Test non-namespace match.
print(FMT_STRING("Hello, world!"));
print(FMT_STRING("Test: {}"), 42);
print(FMT_STRING("Test: {}: {}"), 42, "A");
print(FMT_STRING("Test: {:0}: {} : {}"), 42, "A", myVariable);
print(FMT_STRING("{}, {}, {}"), 42, "A", "B");
print(FMT_STRING("Hello, world!"));
print(FMT_STRING("Test: {}"), 42);
print(FMT_STRING("Test: {}: {}"), 42, "A");
print(FMT_STRING("Test: {:0}: {} : {}"), 42, "A", myVariable);
print(FMT_STRING("{}, {}, {}"), 42, "A", "B");
// Test namespace match.
fmt::print(FMT_STRING("Hello, world!"));
fmt::print(FMT_STRING("Test: {}"), 42);
fmt::print(FMT_STRING("Test: {}: {}"), 42, "A");
fmt::print(FMT_STRING("Test: {:0}: {} : {}"), 42, "A", myVariable);
fmt::print(FMT_STRING("{}, {}, {}"), 42, "A", "B");
fmt::print(FMT_STRING("Hello, world!"));
fmt::print(FMT_STRING("Test: {}"), 42);
fmt::print(FMT_STRING("Test: {}: {}"), 42, "A");
fmt::print(FMT_STRING("Test: {:0}: {} : {}"), 42, "A", myVariable);
fmt::print(FMT_STRING("{}, {}, {}"), 42, "A", "B");
// Test compatibility with existing (should be no change).
fmt::print(FMT_STRING("Hello, world!"));
fmt::print(FMT_STRING("Test: {}"), 42);
fmt::print(FMT_STRING("Test: {}: {}"), 42, "A");
fmt::print(FMT_STRING("Test: {:0}: {} : {}"), 42, "A", myVariable);
fmt::print(FMT_STRING("{}, {}, {}"), 42, "A", "B");
fmt::print(FMT_STRING("Hello, world!"));
fmt::print(FMT_STRING("Test: {}"), 42);
fmt::print(FMT_STRING("Test: {}: {}"), 42, "A");
fmt::print(FMT_STRING("Test: {:0}: {} : {}"), 42, "A", myVariable);
fmt::print(FMT_STRING("{}, {}, {}"), 42, "A", "B");