How to negate filename after a specific term in a regex

Viewed 51

I have a regex that detect urls:

 @"((http|ftp|https)\:\/\/)?([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?";

I am using it with regex.replace to remove urls from text.

I do not want it to replace any word that starts with /images

for example if the text is "this is my text here is a link http://dfdf.com and my is /images/dd.gif" I need the http://dfdf.com replaces but not the /images/dd.gif

my regex replaces the dd.gif so I want to negate any word after images/

any idea how can I fix this ?

2 Answers

You may start matching after a word boundary, and fail the match if it is immediately preceded with a whole "word" images/ using

\b(?<!\bimages/)(?:(?:http|ftp)s?://)?([\w-]+(?:\.[\w-]+)+)([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?

See the regex demo. Details:

  • \b - a word boundary
  • (?<!\bimages/) - no images/ as a whole word is allowed immediately on the left
  • (?:(?:http|ftp)s?://)? - an optional sequence of either http or ftp followed with an optional s and then :// substring
  • ([\w-]+(?:\.[\w-]+)+) - Group 1: one or more word or hyphen chars followed with one or more sequences of a . and then one or more word or hyphen chars
  • ([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])? - an optional Group 2: zero or more word chars or chars from the .,@?^=%&:/~+#- set and then a word char or a char from the @?^=%&/~+#- set.

As an alternative solution, you could match match what you don't want to remove and capture what you do want to remove.

You can use a callback with Replace and test for the existence of group 1. If it is there, return an empty string. If it is not there, return the match to leave it unchanged.

\S*/images\S*|(?<!\S)((?:(?:https?|ftp)://)?[\w-]+(?:(?:\.[\w-]+)+)(?:[\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?)

Explanation

  • \S*/images\S* Match /images preceded and followed by optional non whitespace chars that your want to keep
  • | Or
  • (?<!\S) Assert a whitespace boundary to the left
  • ((?:(?:https?|ftp)://)?[\w-]+(?:(?:\.[\w-]+)+)(?:[\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?) The pattern that you tried with some minor changes to make it a bit shorter

Regex demo (Click on the Table tab to see the matches)

For example

var s = @"this is my text here is a link http://dfdf.com and my is /images/dd.gif";
var regex = new Regex(@"\S*/images\S*|(?<!\S)((?:(?:https?|ftp)://)?[\w-]+(?:(?:\.[\w-]+)+)(?:[\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?)");
var result = regex.Replace(s, match => match.Groups[1].Success ? "" : match.Value);
Console.WriteLine(result);

See a C# demo

Related