Regex pattern definition implementation
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
3
down vote
favorite
My requirement is to design a part of a solution in such matter that specific placeholders are replaces dynamically with a defined logic and new rules can be easily added.
Simple example:
Today is today. The year is year. Last year was year-1.
Should output something like:
Today is 26 Jan 2018. The year is 2018. Last year was 2017.
There are several more business and context specific placeholders and new rules can follow frequently.
As such I came up with this class:
public class PlaceholderDefinition
public string Name get;
public string Pattern get;
private readonly Func<Match, string> _logic;
public PlaceholderDefinition(string name, string pattern, Func<Match, string> logic)
Name = name;
Pattern = pattern;
_logic = logic;
public string Apply(Match match) => _logic.Invoke(match);
To fulfill the above example, I register the following PlaceholderDefinitions
in the service configuration:
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"Today",
@"[tT][oO][dD][aA][yY]",
(_) => DateTime.Today.ToShortDateString()
));
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"Year",
@"[yY][eE][aA][rR]",
(_) => DateTime.Today.Year.ToString()
));
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"YearAddition",
@"(?:[yY][eE][aA][rR])([+-])(d+)",
(m) =>
var operation = m.Groups[1].Value;
int.TryParse(m.Groups[2].Value, out int value);
return (operation == "+" ? DateTime.Today.Year + value : DateTime.Today.Year - value).ToString();
));
The RegisteredPlaceholders
is an enumerable of PlaceholderDefinition held in the container.
The logic of these patterns/placeholders is applied like this:
foreach (var placeholder in RegisteredPlaceholders)
var match = new Regex(placeholder.Pattern).Match(content);
while (match.Success)
content = content.Remove(match.Index, match.Length).Insert(match.Index, placeholder.Apply(match));
match = match.NextMatch();
I decided to take this approach instead of using Regex.Replace()
to not reveal the content or text to the class defining the pattern logic. Maybe there is a more elegant solution, that I didn't come up with.
Every critique, improvement proposal, code smells are welcome.
c# regex
add a comment |Â
up vote
3
down vote
favorite
My requirement is to design a part of a solution in such matter that specific placeholders are replaces dynamically with a defined logic and new rules can be easily added.
Simple example:
Today is today. The year is year. Last year was year-1.
Should output something like:
Today is 26 Jan 2018. The year is 2018. Last year was 2017.
There are several more business and context specific placeholders and new rules can follow frequently.
As such I came up with this class:
public class PlaceholderDefinition
public string Name get;
public string Pattern get;
private readonly Func<Match, string> _logic;
public PlaceholderDefinition(string name, string pattern, Func<Match, string> logic)
Name = name;
Pattern = pattern;
_logic = logic;
public string Apply(Match match) => _logic.Invoke(match);
To fulfill the above example, I register the following PlaceholderDefinitions
in the service configuration:
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"Today",
@"[tT][oO][dD][aA][yY]",
(_) => DateTime.Today.ToShortDateString()
));
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"Year",
@"[yY][eE][aA][rR]",
(_) => DateTime.Today.Year.ToString()
));
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"YearAddition",
@"(?:[yY][eE][aA][rR])([+-])(d+)",
(m) =>
var operation = m.Groups[1].Value;
int.TryParse(m.Groups[2].Value, out int value);
return (operation == "+" ? DateTime.Today.Year + value : DateTime.Today.Year - value).ToString();
));
The RegisteredPlaceholders
is an enumerable of PlaceholderDefinition held in the container.
The logic of these patterns/placeholders is applied like this:
foreach (var placeholder in RegisteredPlaceholders)
var match = new Regex(placeholder.Pattern).Match(content);
while (match.Success)
content = content.Remove(match.Index, match.Length).Insert(match.Index, placeholder.Apply(match));
match = match.NextMatch();
I decided to take this approach instead of using Regex.Replace()
to not reveal the content or text to the class defining the pattern logic. Maybe there is a more elegant solution, that I didn't come up with.
Every critique, improvement proposal, code smells are welcome.
c# regex
2
[tT][oO][dD][aA][yY]
- you know that you could just use theRegexOptions.IgnoreCase
, don't you?
â t3chb0t
Jan 26 at 21:07
I do but it applies to the complete pattern, in some matches case sensitivity is needed.
â Raul Sebastian
Jan 26 at 21:14
2
Why don't you just add another parameter to thePlaceholderDefinition
that is of typeRegexOptions
?
â t3chb0t
Jan 26 at 21:18
that is a good idea, I will do so
â Raul Sebastian
Jan 26 at 21:30
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
My requirement is to design a part of a solution in such matter that specific placeholders are replaces dynamically with a defined logic and new rules can be easily added.
Simple example:
Today is today. The year is year. Last year was year-1.
Should output something like:
Today is 26 Jan 2018. The year is 2018. Last year was 2017.
There are several more business and context specific placeholders and new rules can follow frequently.
As such I came up with this class:
public class PlaceholderDefinition
public string Name get;
public string Pattern get;
private readonly Func<Match, string> _logic;
public PlaceholderDefinition(string name, string pattern, Func<Match, string> logic)
Name = name;
Pattern = pattern;
_logic = logic;
public string Apply(Match match) => _logic.Invoke(match);
To fulfill the above example, I register the following PlaceholderDefinitions
in the service configuration:
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"Today",
@"[tT][oO][dD][aA][yY]",
(_) => DateTime.Today.ToShortDateString()
));
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"Year",
@"[yY][eE][aA][rR]",
(_) => DateTime.Today.Year.ToString()
));
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"YearAddition",
@"(?:[yY][eE][aA][rR])([+-])(d+)",
(m) =>
var operation = m.Groups[1].Value;
int.TryParse(m.Groups[2].Value, out int value);
return (operation == "+" ? DateTime.Today.Year + value : DateTime.Today.Year - value).ToString();
));
The RegisteredPlaceholders
is an enumerable of PlaceholderDefinition held in the container.
The logic of these patterns/placeholders is applied like this:
foreach (var placeholder in RegisteredPlaceholders)
var match = new Regex(placeholder.Pattern).Match(content);
while (match.Success)
content = content.Remove(match.Index, match.Length).Insert(match.Index, placeholder.Apply(match));
match = match.NextMatch();
I decided to take this approach instead of using Regex.Replace()
to not reveal the content or text to the class defining the pattern logic. Maybe there is a more elegant solution, that I didn't come up with.
Every critique, improvement proposal, code smells are welcome.
c# regex
My requirement is to design a part of a solution in such matter that specific placeholders are replaces dynamically with a defined logic and new rules can be easily added.
Simple example:
Today is today. The year is year. Last year was year-1.
Should output something like:
Today is 26 Jan 2018. The year is 2018. Last year was 2017.
There are several more business and context specific placeholders and new rules can follow frequently.
As such I came up with this class:
public class PlaceholderDefinition
public string Name get;
public string Pattern get;
private readonly Func<Match, string> _logic;
public PlaceholderDefinition(string name, string pattern, Func<Match, string> logic)
Name = name;
Pattern = pattern;
_logic = logic;
public string Apply(Match match) => _logic.Invoke(match);
To fulfill the above example, I register the following PlaceholderDefinitions
in the service configuration:
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"Today",
@"[tT][oO][dD][aA][yY]",
(_) => DateTime.Today.ToShortDateString()
));
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"Year",
@"[yY][eE][aA][rR]",
(_) => DateTime.Today.Year.ToString()
));
RegisteredPlaceholders.Add(
new PlaceholderDefinition(
"YearAddition",
@"(?:[yY][eE][aA][rR])([+-])(d+)",
(m) =>
var operation = m.Groups[1].Value;
int.TryParse(m.Groups[2].Value, out int value);
return (operation == "+" ? DateTime.Today.Year + value : DateTime.Today.Year - value).ToString();
));
The RegisteredPlaceholders
is an enumerable of PlaceholderDefinition held in the container.
The logic of these patterns/placeholders is applied like this:
foreach (var placeholder in RegisteredPlaceholders)
var match = new Regex(placeholder.Pattern).Match(content);
while (match.Success)
content = content.Remove(match.Index, match.Length).Insert(match.Index, placeholder.Apply(match));
match = match.NextMatch();
I decided to take this approach instead of using Regex.Replace()
to not reveal the content or text to the class defining the pattern logic. Maybe there is a more elegant solution, that I didn't come up with.
Every critique, improvement proposal, code smells are welcome.
c# regex
asked Jan 26 at 20:52
Raul Sebastian
1184
1184
2
[tT][oO][dD][aA][yY]
- you know that you could just use theRegexOptions.IgnoreCase
, don't you?
â t3chb0t
Jan 26 at 21:07
I do but it applies to the complete pattern, in some matches case sensitivity is needed.
â Raul Sebastian
Jan 26 at 21:14
2
Why don't you just add another parameter to thePlaceholderDefinition
that is of typeRegexOptions
?
â t3chb0t
Jan 26 at 21:18
that is a good idea, I will do so
â Raul Sebastian
Jan 26 at 21:30
add a comment |Â
2
[tT][oO][dD][aA][yY]
- you know that you could just use theRegexOptions.IgnoreCase
, don't you?
â t3chb0t
Jan 26 at 21:07
I do but it applies to the complete pattern, in some matches case sensitivity is needed.
â Raul Sebastian
Jan 26 at 21:14
2
Why don't you just add another parameter to thePlaceholderDefinition
that is of typeRegexOptions
?
â t3chb0t
Jan 26 at 21:18
that is a good idea, I will do so
â Raul Sebastian
Jan 26 at 21:30
2
2
[tT][oO][dD][aA][yY]
- you know that you could just use the RegexOptions.IgnoreCase
, don't you?â t3chb0t
Jan 26 at 21:07
[tT][oO][dD][aA][yY]
- you know that you could just use the RegexOptions.IgnoreCase
, don't you?â t3chb0t
Jan 26 at 21:07
I do but it applies to the complete pattern, in some matches case sensitivity is needed.
â Raul Sebastian
Jan 26 at 21:14
I do but it applies to the complete pattern, in some matches case sensitivity is needed.
â Raul Sebastian
Jan 26 at 21:14
2
2
Why don't you just add another parameter to the
PlaceholderDefinition
that is of type RegexOptions
?â t3chb0t
Jan 26 at 21:18
Why don't you just add another parameter to the
PlaceholderDefinition
that is of type RegexOptions
?â t3chb0t
Jan 26 at 21:18
that is a good idea, I will do so
â Raul Sebastian
Jan 26 at 21:30
that is a good idea, I will do so
â Raul Sebastian
Jan 26 at 21:30
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
3
down vote
accepted
Try to use named group. As your pattern becomes more complex, it will get harder to maintain.
@"(?:[yY][eE][aA][rR])([+-])(d+)"
var operation = m.Groups[1].Value;
int.TryParse(m.Groups[2].Value, out int value);PlaceholderDefinition implementation requires way too much boilerplate code to use:
foreach (var placeholder in RegisteredPlaceholders)
var match = new Regex(placeholder.Pattern).Match(content);
while (match.Success)
content = content.Remove(match.Index, match.Length).Insert(match.Index, placeholder.Apply(match));
match = match.NextMatch();
It could be boiled down to:
content = placeholder.Apply(text);
There is no need to use
Match.NextMatch
&string.Remove
, when you can useRegex.Replace
_logic
seems to be a poorly chosen name. While it describes the essence, but not its concrete job. You should nameFunc
with "Selector, factory, builder, ...", and prefix it with a noun ("result, replacement, ...") and the private member prefix_
(if this is the convention, you choose to follow).
Modified PlaceholderDefinition
class:
public class PlaceholderDefinition
public string Name get;
public Regex Pattern get;
private readonly Func<GroupCollection, object> _replacementSelector;
public PlaceholderDefinition(string name, string pattern, Func<GroupCollection, object> replacementSelector)
: this(name, new Regex(pattern), replacementSelector)
public PlaceholderDefinition(string name, string pattern, RegexOptions options, Func<GroupCollection, object> replacementSelector)
: this(name, new Regex(pattern, options), replacementSelector)
public PlaceholderDefinition(string name, Regex pattern, Func<GroupCollection, object> replacementSelector)
this.Name = name;
this.Pattern = pattern;
this._replacementSelector = replacementSelector;
public string Apply(string input) => Pattern.Replace(input, m => _replacementSelector(m.Groups).ToString());
There is various overloads of ctor
to accommodate different needs, like the one suggested by @t3chb0t. Feels free to add more, if it help you to keep the declarations as clean as possible.
And, the rest of the code:
var text = "Today is today. The year is year. Last year was year-1.";
var placeholders = new List<PlaceholderDefinition>();
placeholders.Add(new PlaceholderDefinition("Today", @"today", RegexOptions.IgnoreCase, _ => DateTime.Today.ToShortDateString()));
placeholders.Add(new PlaceholderDefinition("Year", @"year", RegexOptions.IgnoreCase, _ => DateTime.Today.Year));
placeholders.Add(new PlaceholderDefinition(
"YearAddition",
@"year(?<sign>[+-])(?<value>d+)",
RegexOptions.IgnoreCase,
g => DateTime.Today.Year + int.Parse(g["sign"].Value + g["value"].Value)
));
foreach (var placeholder in placeholders)
text = placeholder.Apply(text);
- The
_replacementSelector
takes inGroupCollection
, so we can skip writingm => m.Group...
, and theobject
TResult allows us to skip the necessary.ToString()
or a parenthesis on binary operation. int.Parse
will parse number prefixed by a+
sign as positive number, allowing us to skip the ternary operation.
Thanks for the effort. These are some great suggestions.
â Raul Sebastian
Jan 26 at 22:38
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
accepted
Try to use named group. As your pattern becomes more complex, it will get harder to maintain.
@"(?:[yY][eE][aA][rR])([+-])(d+)"
var operation = m.Groups[1].Value;
int.TryParse(m.Groups[2].Value, out int value);PlaceholderDefinition implementation requires way too much boilerplate code to use:
foreach (var placeholder in RegisteredPlaceholders)
var match = new Regex(placeholder.Pattern).Match(content);
while (match.Success)
content = content.Remove(match.Index, match.Length).Insert(match.Index, placeholder.Apply(match));
match = match.NextMatch();
It could be boiled down to:
content = placeholder.Apply(text);
There is no need to use
Match.NextMatch
&string.Remove
, when you can useRegex.Replace
_logic
seems to be a poorly chosen name. While it describes the essence, but not its concrete job. You should nameFunc
with "Selector, factory, builder, ...", and prefix it with a noun ("result, replacement, ...") and the private member prefix_
(if this is the convention, you choose to follow).
Modified PlaceholderDefinition
class:
public class PlaceholderDefinition
public string Name get;
public Regex Pattern get;
private readonly Func<GroupCollection, object> _replacementSelector;
public PlaceholderDefinition(string name, string pattern, Func<GroupCollection, object> replacementSelector)
: this(name, new Regex(pattern), replacementSelector)
public PlaceholderDefinition(string name, string pattern, RegexOptions options, Func<GroupCollection, object> replacementSelector)
: this(name, new Regex(pattern, options), replacementSelector)
public PlaceholderDefinition(string name, Regex pattern, Func<GroupCollection, object> replacementSelector)
this.Name = name;
this.Pattern = pattern;
this._replacementSelector = replacementSelector;
public string Apply(string input) => Pattern.Replace(input, m => _replacementSelector(m.Groups).ToString());
There is various overloads of ctor
to accommodate different needs, like the one suggested by @t3chb0t. Feels free to add more, if it help you to keep the declarations as clean as possible.
And, the rest of the code:
var text = "Today is today. The year is year. Last year was year-1.";
var placeholders = new List<PlaceholderDefinition>();
placeholders.Add(new PlaceholderDefinition("Today", @"today", RegexOptions.IgnoreCase, _ => DateTime.Today.ToShortDateString()));
placeholders.Add(new PlaceholderDefinition("Year", @"year", RegexOptions.IgnoreCase, _ => DateTime.Today.Year));
placeholders.Add(new PlaceholderDefinition(
"YearAddition",
@"year(?<sign>[+-])(?<value>d+)",
RegexOptions.IgnoreCase,
g => DateTime.Today.Year + int.Parse(g["sign"].Value + g["value"].Value)
));
foreach (var placeholder in placeholders)
text = placeholder.Apply(text);
- The
_replacementSelector
takes inGroupCollection
, so we can skip writingm => m.Group...
, and theobject
TResult allows us to skip the necessary.ToString()
or a parenthesis on binary operation. int.Parse
will parse number prefixed by a+
sign as positive number, allowing us to skip the ternary operation.
Thanks for the effort. These are some great suggestions.
â Raul Sebastian
Jan 26 at 22:38
add a comment |Â
up vote
3
down vote
accepted
Try to use named group. As your pattern becomes more complex, it will get harder to maintain.
@"(?:[yY][eE][aA][rR])([+-])(d+)"
var operation = m.Groups[1].Value;
int.TryParse(m.Groups[2].Value, out int value);PlaceholderDefinition implementation requires way too much boilerplate code to use:
foreach (var placeholder in RegisteredPlaceholders)
var match = new Regex(placeholder.Pattern).Match(content);
while (match.Success)
content = content.Remove(match.Index, match.Length).Insert(match.Index, placeholder.Apply(match));
match = match.NextMatch();
It could be boiled down to:
content = placeholder.Apply(text);
There is no need to use
Match.NextMatch
&string.Remove
, when you can useRegex.Replace
_logic
seems to be a poorly chosen name. While it describes the essence, but not its concrete job. You should nameFunc
with "Selector, factory, builder, ...", and prefix it with a noun ("result, replacement, ...") and the private member prefix_
(if this is the convention, you choose to follow).
Modified PlaceholderDefinition
class:
public class PlaceholderDefinition
public string Name get;
public Regex Pattern get;
private readonly Func<GroupCollection, object> _replacementSelector;
public PlaceholderDefinition(string name, string pattern, Func<GroupCollection, object> replacementSelector)
: this(name, new Regex(pattern), replacementSelector)
public PlaceholderDefinition(string name, string pattern, RegexOptions options, Func<GroupCollection, object> replacementSelector)
: this(name, new Regex(pattern, options), replacementSelector)
public PlaceholderDefinition(string name, Regex pattern, Func<GroupCollection, object> replacementSelector)
this.Name = name;
this.Pattern = pattern;
this._replacementSelector = replacementSelector;
public string Apply(string input) => Pattern.Replace(input, m => _replacementSelector(m.Groups).ToString());
There is various overloads of ctor
to accommodate different needs, like the one suggested by @t3chb0t. Feels free to add more, if it help you to keep the declarations as clean as possible.
And, the rest of the code:
var text = "Today is today. The year is year. Last year was year-1.";
var placeholders = new List<PlaceholderDefinition>();
placeholders.Add(new PlaceholderDefinition("Today", @"today", RegexOptions.IgnoreCase, _ => DateTime.Today.ToShortDateString()));
placeholders.Add(new PlaceholderDefinition("Year", @"year", RegexOptions.IgnoreCase, _ => DateTime.Today.Year));
placeholders.Add(new PlaceholderDefinition(
"YearAddition",
@"year(?<sign>[+-])(?<value>d+)",
RegexOptions.IgnoreCase,
g => DateTime.Today.Year + int.Parse(g["sign"].Value + g["value"].Value)
));
foreach (var placeholder in placeholders)
text = placeholder.Apply(text);
- The
_replacementSelector
takes inGroupCollection
, so we can skip writingm => m.Group...
, and theobject
TResult allows us to skip the necessary.ToString()
or a parenthesis on binary operation. int.Parse
will parse number prefixed by a+
sign as positive number, allowing us to skip the ternary operation.
Thanks for the effort. These are some great suggestions.
â Raul Sebastian
Jan 26 at 22:38
add a comment |Â
up vote
3
down vote
accepted
up vote
3
down vote
accepted
Try to use named group. As your pattern becomes more complex, it will get harder to maintain.
@"(?:[yY][eE][aA][rR])([+-])(d+)"
var operation = m.Groups[1].Value;
int.TryParse(m.Groups[2].Value, out int value);PlaceholderDefinition implementation requires way too much boilerplate code to use:
foreach (var placeholder in RegisteredPlaceholders)
var match = new Regex(placeholder.Pattern).Match(content);
while (match.Success)
content = content.Remove(match.Index, match.Length).Insert(match.Index, placeholder.Apply(match));
match = match.NextMatch();
It could be boiled down to:
content = placeholder.Apply(text);
There is no need to use
Match.NextMatch
&string.Remove
, when you can useRegex.Replace
_logic
seems to be a poorly chosen name. While it describes the essence, but not its concrete job. You should nameFunc
with "Selector, factory, builder, ...", and prefix it with a noun ("result, replacement, ...") and the private member prefix_
(if this is the convention, you choose to follow).
Modified PlaceholderDefinition
class:
public class PlaceholderDefinition
public string Name get;
public Regex Pattern get;
private readonly Func<GroupCollection, object> _replacementSelector;
public PlaceholderDefinition(string name, string pattern, Func<GroupCollection, object> replacementSelector)
: this(name, new Regex(pattern), replacementSelector)
public PlaceholderDefinition(string name, string pattern, RegexOptions options, Func<GroupCollection, object> replacementSelector)
: this(name, new Regex(pattern, options), replacementSelector)
public PlaceholderDefinition(string name, Regex pattern, Func<GroupCollection, object> replacementSelector)
this.Name = name;
this.Pattern = pattern;
this._replacementSelector = replacementSelector;
public string Apply(string input) => Pattern.Replace(input, m => _replacementSelector(m.Groups).ToString());
There is various overloads of ctor
to accommodate different needs, like the one suggested by @t3chb0t. Feels free to add more, if it help you to keep the declarations as clean as possible.
And, the rest of the code:
var text = "Today is today. The year is year. Last year was year-1.";
var placeholders = new List<PlaceholderDefinition>();
placeholders.Add(new PlaceholderDefinition("Today", @"today", RegexOptions.IgnoreCase, _ => DateTime.Today.ToShortDateString()));
placeholders.Add(new PlaceholderDefinition("Year", @"year", RegexOptions.IgnoreCase, _ => DateTime.Today.Year));
placeholders.Add(new PlaceholderDefinition(
"YearAddition",
@"year(?<sign>[+-])(?<value>d+)",
RegexOptions.IgnoreCase,
g => DateTime.Today.Year + int.Parse(g["sign"].Value + g["value"].Value)
));
foreach (var placeholder in placeholders)
text = placeholder.Apply(text);
- The
_replacementSelector
takes inGroupCollection
, so we can skip writingm => m.Group...
, and theobject
TResult allows us to skip the necessary.ToString()
or a parenthesis on binary operation. int.Parse
will parse number prefixed by a+
sign as positive number, allowing us to skip the ternary operation.
Try to use named group. As your pattern becomes more complex, it will get harder to maintain.
@"(?:[yY][eE][aA][rR])([+-])(d+)"
var operation = m.Groups[1].Value;
int.TryParse(m.Groups[2].Value, out int value);PlaceholderDefinition implementation requires way too much boilerplate code to use:
foreach (var placeholder in RegisteredPlaceholders)
var match = new Regex(placeholder.Pattern).Match(content);
while (match.Success)
content = content.Remove(match.Index, match.Length).Insert(match.Index, placeholder.Apply(match));
match = match.NextMatch();
It could be boiled down to:
content = placeholder.Apply(text);
There is no need to use
Match.NextMatch
&string.Remove
, when you can useRegex.Replace
_logic
seems to be a poorly chosen name. While it describes the essence, but not its concrete job. You should nameFunc
with "Selector, factory, builder, ...", and prefix it with a noun ("result, replacement, ...") and the private member prefix_
(if this is the convention, you choose to follow).
Modified PlaceholderDefinition
class:
public class PlaceholderDefinition
public string Name get;
public Regex Pattern get;
private readonly Func<GroupCollection, object> _replacementSelector;
public PlaceholderDefinition(string name, string pattern, Func<GroupCollection, object> replacementSelector)
: this(name, new Regex(pattern), replacementSelector)
public PlaceholderDefinition(string name, string pattern, RegexOptions options, Func<GroupCollection, object> replacementSelector)
: this(name, new Regex(pattern, options), replacementSelector)
public PlaceholderDefinition(string name, Regex pattern, Func<GroupCollection, object> replacementSelector)
this.Name = name;
this.Pattern = pattern;
this._replacementSelector = replacementSelector;
public string Apply(string input) => Pattern.Replace(input, m => _replacementSelector(m.Groups).ToString());
There is various overloads of ctor
to accommodate different needs, like the one suggested by @t3chb0t. Feels free to add more, if it help you to keep the declarations as clean as possible.
And, the rest of the code:
var text = "Today is today. The year is year. Last year was year-1.";
var placeholders = new List<PlaceholderDefinition>();
placeholders.Add(new PlaceholderDefinition("Today", @"today", RegexOptions.IgnoreCase, _ => DateTime.Today.ToShortDateString()));
placeholders.Add(new PlaceholderDefinition("Year", @"year", RegexOptions.IgnoreCase, _ => DateTime.Today.Year));
placeholders.Add(new PlaceholderDefinition(
"YearAddition",
@"year(?<sign>[+-])(?<value>d+)",
RegexOptions.IgnoreCase,
g => DateTime.Today.Year + int.Parse(g["sign"].Value + g["value"].Value)
));
foreach (var placeholder in placeholders)
text = placeholder.Apply(text);
- The
_replacementSelector
takes inGroupCollection
, so we can skip writingm => m.Group...
, and theobject
TResult allows us to skip the necessary.ToString()
or a parenthesis on binary operation. int.Parse
will parse number prefixed by a+
sign as positive number, allowing us to skip the ternary operation.
edited Jan 26 at 22:45
answered Jan 26 at 22:33
Xiaoy312
2,767915
2,767915
Thanks for the effort. These are some great suggestions.
â Raul Sebastian
Jan 26 at 22:38
add a comment |Â
Thanks for the effort. These are some great suggestions.
â Raul Sebastian
Jan 26 at 22:38
Thanks for the effort. These are some great suggestions.
â Raul Sebastian
Jan 26 at 22:38
Thanks for the effort. These are some great suggestions.
â Raul Sebastian
Jan 26 at 22:38
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f186088%2fregex-pattern-definition-implementation%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
2
[tT][oO][dD][aA][yY]
- you know that you could just use theRegexOptions.IgnoreCase
, don't you?â t3chb0t
Jan 26 at 21:07
I do but it applies to the complete pattern, in some matches case sensitivity is needed.
â Raul Sebastian
Jan 26 at 21:14
2
Why don't you just add another parameter to the
PlaceholderDefinition
that is of typeRegexOptions
?â t3chb0t
Jan 26 at 21:18
that is a good idea, I will do so
â Raul Sebastian
Jan 26 at 21:30