I am using MVC3, C#, .net4.0
I have objects that contain a search string with which I can use to search for the relevant objects ie for 4 objects:
[car:vw:engine:1800]
[car:vw:engine:Diesel 1800]
[car:vw:engine:1600]
[car:ford:engine:1800]
I would like to search for objects that have a make of "vw" and "1800" engine.
I could try Contains():
SearchString.Contains("vw:engine:1800")
Which will return just one object.
I need something like:
SearchString.Contains("vw:engine:*1800")
Where * is a wildcard and would pick up :
[car:vw:engine:1800]
[car:vw:engine:Diesel 1800]
The only way around this, at present, would be:
SearchString.Contains("vw:engine:1800") or
SearchString.Contains("vw:engine:Diesel 1800")
Is there a simple way to do this using a mainstream .net function like Contains(), if not Contains() itself.
There is a good reason for me using a search string like this, but this is not part of the question.
You can use regular expressions to check if SearchString is a match. .* means zero or more of any characters and is used in place of your wildcard.
string pattern = #"^\[car:vw:engine:.*1800]$";
bool matches = Regex.IsMatch(SearchString, pattern);
Generally I'd prefer the regular expressions.
In your particular case you could use something like this:
string car1 = "[car:vw:engine:Diesel 1800]";
string car2 = "[car:vw:engine:1800]";
var tokens1 = car1.Substring(1, car1.Length - 2).Split(':');
var tokens2 = car2.Substring(1, car2.Length - 2).Split(':');
bool IsMatch1 = tokens1[3].EndsWith("1800");
bool IsMatch2 = tokens2[3].EndsWith("1800");
Related
Is it possible to do a string interpolation formatting a substring of a string?
I have been searching the Microsoft documents about string interpolation but cannot get a working sample done. reference.
Currently I have :
var description = "the quick brown fox";
var result = $"{description.Substring(0, description.Length < 10 ? description.Length : 10)} jumps..",
using string interpolation I would ideally like to use:
var description = "the quick brown fox";
var result = $"{description:10} jumps..",
editted
I would expect the output of result to be :
The quick jumps..
You can use ranges (C# 8):
var description = "the quick brown fox";
var result = $"{description[..10]} jumps..";
You can use Take method:
description.Take(10)
Unfortunately, this method returns IEnumerable which cannot be directly converted to string (ToString method would return name of type as usually when using it on IEnumerable).
You can't create string using it, because string constructor requires array of chars, so the easiest solution will be:
new string(description.Take(10).ToArray())
Still, such code makes it harder to read if you want to use it few times, so you can create extension method:
public static string TakeFirst(this string text, int number)
{
if (text == null)
return null;
return new string(text.Take(number).ToArray());
}
Then you can just use it:
$"{description.TakeFirst(10)} jumps..";
EDIT: As mentioned in comments, because of allocation of array each time this method is called, there might occur serious performance issues. You can avoid them by implementing TakeFirst method using Substring instead of Take(x).ToArray() solution.
As the question was:
"Is it possible to do a string interpolation formatting a substring of a string?"
In such a manner:
var result = $"{description:10} jumps..",
The answer given from #JohnSkeet and #JeroenMostert was most acurate:
"No, it is not possible."
There are various ways to simplify the call. thanks for #PiotrWojsa for pointing that out. however that doesnt involve the interpolation part..
I have an issue with a string containing the plus sign (+).
I want to split that string (or if there is some other way to solve my problem)
string ColumnPlusLevel = "+-J10+-J10+-J10+-J10+-J10";
string strpluslevel = "";
strpluslevel = ColumnPlusLevel;
string[] strpluslevel_lines = Regex.Split(strpluslevel, "+");
foreach (string line in strpluslevel_lines)
{
MessageBox.Show(line);
strpluslevel_summa = strpluslevel_summa + line;
}
MessageBox.Show(strpluslevel_summa, "summa sumarum");
The MessageBox is for my testing purpose.
Now... The ColumnPlusLevel string can have very varied entry but it is always a repeated pattern starting with the plus sign.
i.e. "+MJ+MJ+MJ" or "+PPL14.1+PPL14.1+PPL14.1" as examples.
(It comes form Another software and I cant edit the output from that software)
How can I find out what that pattern is that is being repeated?
That in this exampels is the +-J10 or +MJ or +PPL14.1
In my case above I have tested it by using only a MessageBox to show the result but I want the repeated pattering stored in a string later on.
Maybe im doing it wrong by using Split, maybe there is another solution.
Maybe I use Split in the wrong way.
Hope you understand my problem and the result I want.
Thanks for any advice.
/Tomas
How can I find out what that pattern is that is being repeated?
Maybe i didn't understand the requirement fully, but isn't it easy as:
string[] tokens = ColumnPlusLevel.Split(new[]{'+'}, StringSplitOptions.RemoveEmptyEntries);
string first = tokens[0];
bool repeatingPattern = tokens.Skip(1).All(s => s == first);
If repeatingPattern is true you know that the pattern itself is first.
Can you maybe explain how the logic works
The line which contains tokens.Skip(1) is a LINQ query, so you need to add using System.Linq at the top of your code file. Since tokens is a string[] which implements IEnumerable<string> you can use any LINQ (extension-)method. Enumerable.Skip(1) will skip the first because i have already stored that in a variable and i want to know if all others are same. Therefore i use All which returns false as soon as one item doesn't match the condition(so one string is different to the first). If all are same you know that there is a repeating pattern which is already stored in the variable first.
You should use String.Split function :
string pattern = ColumnPlusLevel.Split("+")[0];
...but it is always a repeated pattern starting with the plus sign.
Why do you even need String.Split() here if the pattern always only repeats itself?
string input = #"+MJ+MJ+MJ";
int indexOfSecondPlus = input.IndexOf('+', 1);
string pattern = input.Remove(indexOfSecondPlus, input.Length - indexOfSecondPlus);
//pattern is now "+MJ"
No need of string split, no need to use LinQ
String has a method called Split which let's you split/divide the string based on a given character/character-set:
string givenString = "+-J10+-J10+-J10+-J10+-J10"'
string SplittedString = givenString.Split("+")[0] ///Here + is the character based on which the string would be splitted and 0 is the index number
string result = SplittedString.Replace("-","") //The mothod REPLACE replaces the given string with a targeted string,i added this so that you can get the numbers only from the string
I'm not sure if it's okay to ask... But here goes.
I implemented a method that parses a string using regex, each matching are parsed through the delegates with an order ( actually, order is not important-- I think, wait, is it? ... But I wrote it this way, and it's not fully tested ):
Pattern Regex.Replace: #"(?<!\\)\$.+?\$" then String.Replace: #"\$", #"$"; Replace string enclosed by dollar sign. Ignores backslash ones, then erases backslash. Ex: "$global name$" -> "motherofglobalvar", "Money \$9000" -> "Money $9000"
Pattern Regex.Replace #"(?<!\\)%.+?%" then String.Replace #"\%", #"%"; Replace string enclosed by percentage sign. Ignores backslash ones, then erase backslash. Same as previous example: "%local var%" -> "lordoflocalvar", "It's over 9000\%" -> "It's over 9000%"
Pattern Regex.Replace #"(?<!\\)#" then String.Replace #"\#", #"#"; Replace char '#' with whitespace, ' '. But ignore backslash ones, then erase the backslash. Ex: "I#hit#the#ground#too#hard" -> "I hit the ground too hard", "qw\#op" -> "qw#op"
What I've done without much experience (I think):
//parse variable
public static string ParseVariable(string text)
{
return Regex.Replace(Regex.Replace(Regex.Replace(text, #"(?<!\\)\$.+?\$", match =>
{
string trim = match.Value.Trim('$');
string trimUpper = trim.ToUpper();
return variableGlobal.ContainsKey(trim) ? variableGlobal[trim] : match.Value;
}).Replace(#"\$", #"$"), #"(?<!\\)%.+?%", match =>
{
string trim = match.Value.Trim('%');
string trimUpper = trim.ToUpper();
return variableLocal.ContainsKey(trim) ? variableLocal[trim] : match.Value;
}).Replace(#"\%", #"%"), #"(?<!\\)#", " ").Replace(#"\#", #"#");
}
In short, what I used is: Regex.Replace().Replace()
Since I need to parse 3 kinds of symbols, I chained it as following: Regex.Replace(Regex.Replace(Regex.Replace().Replace()).Replace()).Replace()
Is there any more efficient way than this? I mean, like without need to go through the text 6 times? (3 times regex.replace, 3 times string.replace, where each replace modifies the text to be used by the next replace )
Or is it the best way it can do?
Thanks.
Here's a unique take on the problem, I think. You can build a class that will be used to construct the overall pattern piece-by-piece. This class will be responsible for the generating of the MatchEvaluator delegate that will be passed to Replace as well.
class RegexReplacer
{
public string Pattern { get; private set; }
public string Replacement { get; private set; }
public string GroupName { get; private set; }
public RegexReplacer NextReplacer { get; private set; }
public RegexReplacer(string pattern, string replacement, string groupName, RegexReplacer nextReplacer = null)
{
this.Pattern = pattern;
this.Replacement = replacement;
this.GroupName = groupName;
this.NextReplacer = nextReplacer;
}
public string GetAggregatedPattern()
{
string constructedPattern = this.Pattern;
string alternation = (this.NextReplacer == null ? string.Empty : "|" + this.NextReplacer.GetAggregatedPattern()); // If there isn't another replacer, then we won't have an alternation; otherwise, we build an alternation between this pattern and the next replacer's "full" pattern
constructedPattern = string.Format("(?<{0}>{1}){2}", this.GroupName, this.Pattern, alternation); // The (?<XXX>) syntax builds a named capture group. This is used by our GetReplacementDelegate metho.
return constructedPattern;
}
public MatchEvaluator GetReplaceDelegate()
{
return (match) =>
{
if (match.Groups[this.GroupName] != null && match.Groups[this.GroupName].Length > 0) // Did we get a hit on the group name?
{
return this.Replacement;
}
else if (this.NextReplacer != null) // No? Then is there another replacer to inspect?
{
MatchEvaluator next = this.NextReplacer.GetReplaceDelegate();
return next(match);
}
else
{
return match.Value; // No? Then simply return the value
}
};
}
}
It should be obvious as to what Pattern and Replacement represent. GroupName is kind of a hack to let the replacement evaluator know which RegexReplacer fragment resulted in the match. NextReplacer points to another replacer instance that holds a different pattern fragment (et al.).
The idea here is to have a kind of linked list of objects that will represent the overall pattern. You can call GetAggregatedPattern on the outer-most replacer to get the full pattern--each replacer calls the next replacer's GetAggregatedPattern to get that replacer's patter fragment, to which it concatenates its own fragment. The GetReplacementDelegate generates a MatchEvaluator. This MatchEvaluator will compare its own GroupName to the Match's captured groups. If the group name was captured, then we have a hit, and we return this replacer's Replacement value. Otherwise, we step into the next replacer (if there is one) and repeat the group name comparison. If there is no hit on any replacer, then we simply yield back the original value (i.e. what was matched by the pattern; this should be rare).
The usage of such might look like this:
string target = #"$global name$ Money \$9000 %local var% It's over 9000\% I#hit#the#ground#too#hard qw\#op";
RegexReplacer dollarWrapped = new RegexReplacer(#"(?<!\\)\$[^$]+\$", "motherofglobalvar", "dollarWrapped");
RegexReplacer slashDollar = new RegexReplacer(#"\\\$", string.Empty, "slashDollar", dollarWrapped);
RegexReplacer percentWrapped = new RegexReplacer(#"(?<!\\)%[^%]+%", "lordoflocalvar", "percentWrapped", slashDollar);
RegexReplacer slashPercent = new RegexReplacer(#"\\%", string.Empty, "slashPercent", percentWrapped);
RegexReplacer singleAt = new RegexReplacer(#"(?<!\\)#", " ", "singleAt", slashPercent);
RegexReplacer slashAt = new RegexReplacer(#"\\#", "#", "slashAt", singleAt);
RegexReplacer replacer = slashAt;
string pattern = replacer.GetAggregatedPattern();
MatchEvaluator evaluator = replacer.GetReplaceDelegate();
string result = Regex.Replace(target, pattern, evaluator);
Because you want each replacer to know if it got a hit, and because we are hacking this by using group names, you want to make sure that each group name is distinct. A simple way to ensure this would be to use a name that's identical to the variable name since you can't have two variables with the same name within the same scope.
You can see above that I am building each part of the pattern separately, but as I build, I pass the previous replacer as a 4th parameter to the current replacer. This builds the chain of replacers. Once built, I use the last replacer constructed in order to generate the overall pattern and evaluator. If you use anything but, then you will only have part of the overall pattern. Finally, it's simply a matter of passing the generated pattern and evaluator to the Replace method.
Keep in mind that this approach was targeted more at the problem as described. It may work in more general scenarios, but I've only worked with what you've presented. Also, since this is more of a parsing question, a parser may be the proper route to take--although the learning curve is going to be higher.
Also keep in mind that I haven't profiled this code. It certainly doesn't loop over the target string multiple times, but it does involve additional method calls during replacement. You would certainly want to test it in your environment.
I want to be able to use the contains function the same way the like operator works in sql. So when I call .contains(%This%%%%%%is%%my%string%%) from a list or whatever such as "This is my string " then the function will return true. I've done a lot of searching and it seems like a lot of people would like this function. So how can this be done or how can a custom like function with the same functionality be made?
EDIT
Thank you, for the quick response. I was able to use a regular expressions inside of my own custom Like function. Below is the code for anyone else who wants to use something similar to SQL Like. In this code the user would input the databaze value and then spaces in that value are replaced with .* to ignore anything in-between the values.Just like using the % to replace spaces and values in SQL. I can then use .Like on my string value called testValue that I am searching through to return true or false depending on if the words or whatever are in my string. I also added ToUpper to ignore the case.
//C# Like function
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
namespace sqllinqstuff
{
class Program
{
static void Main(string[] args)
{
string testValue = "Big RED Car";
string databaze = "big red CAR";
string databaze3 = databaze.Replace(" ", ".*");
databaze3 = databaze3.Replace(" ", ".*");
Console.WriteLine(databaze3);
Console.WriteLine(testValue.Like(databaze3));
Console.Read();
}
}
public static class CaseyStringExtension
{
public static bool Like(this string str,string value)
{
if (!string.IsNullOrEmpty(str))
{
Regex r = new Regex(value.ToUpper());
if (r.IsMatch(str.ToUpper()))
return true;
}
return false;
}
}
}
The result of this test will be true.
The way this would be done is with Regex. The syntax is not the same as a SQL LIKE query so there will be a bit of a learning curve. This is a good tutorial site I often reference, it can get you started with the basics.
Translating your original string you asked about, the regex search pattern would be
.*This.*is.*my.*string.*
Once you get good at it you can do searches like this one I helped create for a password complexity checker
(?=^.{8,}$)(?=.*[a-z])(?=.*[A-Z])(?=.*[\W_])(?=^.*[^\s].*$).*$
The above search looks for a string that has at least 8 characters with at least one lower case letter, one upper case letter, one special character, and no white-space characters.
I have the following regex (long, I know):
(?-mix:((?-mix:(?-mix:\{\%).*?(?-mix:\%\})|(?-mix:\{\{).*?(?-mix:\}\}?))
|(?-mix:\{\{|\{\%)))
that I'm using to split a string. It matches correctly in C#, but when I moved the code to Java, it doesn't match. Is there any particular feature of this regex that is C#-only?
The source is produced as:
String source = Pattern.quote("{% assign foo = values %}.{{ foo[0] }}.");
While in C# it's:
string source = #"{% assign foo = values %}.{{ foo[0] }}.";
The C# version is like this:
string[] split = Regex.split(source, regex);
In Java I tried both:
String[] split = source.split(regex);
and also
Pattern p = Pattern.compile(regex);
String[] split = p.split(source);
Here is a sample program with your code: http://ideone.com/hk3uy
There is a major difference here between Java and other languages: Java does not add captured groups as tokens in the result array (example). That means that all delimiters are removed from result, though they would be included in .Net.
The only alternative I know is not to use split, but getting a list of matches and splitting manually.
I think the problem is with how you're defining source. On my system, this:
String source = Pattern.quote("{% assign foo = values %}.{{ foo[0] }}.");
is equivalent to this:
String source = "\\Q{% assign foo = values %}.{{ foo[0] }}.\\E";
(that is, it adds a stray \Q and \E), but the way the method is defined, your Java implementation could treat it as equivalent to this:
String source = "\\{% assign foo = values %\\}\\.\\{\\{ foo\\[0\\] \\}\\}\\.";
(that is, inserting lots of backslashes).
Your regex itself seems fine. This program:
public static void main(final String... args)
{
final Pattern p = Pattern.compile("(?-mix:((?-mix:(?-mix:\\{\\%).*?(?-mix:\\%\\})|(?-mix:\\{\\{).*?(?-mix:\\}\\}?))|(?-mix:\\{\\{|\\{\\%)))");
for(final String s : p.split("a{%b%}c{{d}}e{%f%}g{{h}}i{{j{%k"))
System.out.println(s);
}
prints
a
c
e
g
i
j
k
that is, it successfully treats {%b%}, {{d}}, {%f%}, {{h}}, {{, and {% as split-points, with all the non-greediness you'd expect. But tor the record, it also works if I strip p down to just
Pattern.compile("\\{%.*?%\\}|\\{\\{.*?\\}\\}?|\\{\\{|\\{%");
;-)
use \\{ instead of \{ and for other symbols too