This is my text:
text=
CREATE TABLE `t1` (
`ID_B` varchar(20) NOT NULL,
CONSTRAINT `FK_IDBRIG1` FOREIGN KEY (`ID_P`) REFERENCES `existing`
(`ID_PUEBLO`) ON DELETE CASCADE ON UPDATE CASCADE
CREATE TABLE `t2` (
`ID_B2` varchar(20) NOT NULL,
`ID_P` varchar(5) NOT NULL
CONSTRAINT `FK_IDP_BRIG` FOREIGN KEY (`ID_PUEBLO`) REFERENCES `nonexisting`
(`ID_PUEBLO`) ON DELETE CASCADE ON UPDATE CASCADE
--
I want to replace all matches of "REFERENCES word " by "REFERENCES word_new " ONLY if word exists in a list, so it would be something like:
List<String> my_accepted_words = new List<string>();
my_accepted_words.Add("existing");
text = Regex.Replace(text, @" REFERENCES\s `(\w )`", "REFERENCES `$1_new`");
But it still misses the condition that (\w ) should match any item in my_accepted_words
Expected result would be:
text=
CREATE TABLE `t1` (
`ID_B` varchar(20) NOT NULL,
CONSTRAINT `FK_IDBRIG1` FOREIGN KEY (`ID_P`) REFERENCES `existing_new`
(`ID_PUEBLO`) ON DELETE CASCADE ON UPDATE CASCADE
CREATE TABLE `t2` (
`ID_B2` varchar(20) NOT NULL,
`ID_P` varchar(5) NOT NULL
CONSTRAINT `FK_IDP_BRIG` FOREIGN KEY (`ID_PUEBLO`) REFERENCES `nonexisting`
(`ID_PUEBLO`) ON DELETE CASCADE ON UPDATE CASCADE
--
I have an idea of how could i do it:
Apply a Regex replacement for each word in my_accepted_words
foreach (string word in my_accepted_words)
{
text = Regex.Replace(text, @" REFERENCES\s `" word "`", "REFERENCES `" word "_new`");
}
But what i would really like to do is somehow capture all matches, check if they accomplish the condition of existing in the List and replace/not replace according to it. Perhaps in the future i will need to apply more complex conditions.
Any way to do this?
Thanks
CodePudding user response:
If your words do not contain any characters which would be considered "special" by the regular expressions language, then you can build them into your pattern:
string pattern = @" REFERENCES\s `(" string.Join("|", my_accepted_words) ")`";
text = Regex.Replace(text, pattern, "REFERENCES `$1_new`");
Otherwise, you could use a match evaluator:
text = Regex.Replace(text, @" REFERENCES\s `(\w )`", match =>
{
string word = match.Groups[1].Value;
if (!my_accepted_words.Contains(word)) return match.Value;
return $" REFERENCES `{word}_new`";
});
CodePudding user response:
A MatchEvaluator can do this. It's a method that the regex will call when it finds a match, and it will pass the match so the method can propose some alternative value for replacement
var text = "SOMETHING REFERENCES `old` AS WHATEVER";
//instead of a list let's have a Dictionary that specifies replacements
var dict = new Dictionary<string, string>(){ { "old" , " REFERENCES `some_new_thing`" } };
var r = Regex.Replace(
text,
@" REFERENCES\s `(\w )`",
m => dict.GetValueOrDefault(m.Groups[1].Value, m.Groups[0].Value)
);
The last bit is the interesting part. It's a lambda that accepts a Match m - if the captured group value old is contained in the dictionary, the replacement value is provided from the dictionary. If the entry is not in the dictonary, the whole matched value is returned as the replacement (effectively a non-op)
If you want just "does the list contain X" then you could perhaps just have:
var text = "SOMETHING REFERENCES `old` AS WHATEVER";
var hs = new HashSet<string>(){ "old" };
var r = Regex.Replace(
text,
@" REFERENCES\s `(\w )`",
m => hs.Contains(m.Groups[1].Value) ? $" REFERENCES `{Groups[1].Value}_new`" : m.Groups[0].Value
);
It's important to note that you have to form the value you want: a MatchEvaluator takes a Match and should return a string that shall be the replacement, so you're responsible for creating the entire replacement in the "in list" or "not in list" case; that means either returning the original string (conveniently stored in Groups[0]) or an altered one. You can't return a string that e.g. contains $1
All in if you have a set of replacements to apply, it might be least confusing to not use a capture group and put the whole match in the dictionary:
var text = "SOMETHING REFERENCES `old` AS WHATEVER";
//instead of a list let's have a Dictionary that specifies replacements
var dict = new Dictionary<string, string>(){
{ "REFERENCES `old`" , " REFERENCES `some_new_thing`" },
{ "REFERENCES `new`" , " REFERENCES `some_other_thing`" }
};
var r = Regex.Replace(
text,
@" REFERENCES\s `\w `",
m => dict.GetValueOrDefault(m.Groups[0].Value, m.Groups[0].Value)
);
Bear in mind that a confusion might arise fi the Regex is matching case insensitive, because the Dictionary lookup will be by default case sensitive; make sure they're aligned to avoid KeyNotFound errors
