Bokambo
Bokambo

Reputation: 4480

String split with specified string without delimeter

Updated - When searched value is in middle

string text = "Trio charged over alleged $100m money laundering syndicate at Merrylands, Guildford West";
string searchtext= "charged over";
string[] fragments = text.Split(new string[] { searchtext }, StringSplitOptions.None);

    //Fragments
   //if [0] is blank searched text is in the beginning - searchedtext + [1]
  //if [1] is blank searched text is in the end - [0] + searched text
  // If searched text is in middle then both items has value - [0] + seachedtext + [1]

 //This loop will execute only two times because it can have maximum 2 values, issue will
 //come when searched value is in middle (loop should run 3 times) as for the searched value i have to apply differnt logic (like change background color of the text)
 // and dont change background color for head and tail
 //How do i insert searched value in middle of [0] and [1] ??

I am having a string without delimeter which i am trying to split based on searched string. My requirement is split the string into two , one part contains string without the searchtext and other contains searchtext like below-

 Original String - "Bitcoin ATMs Highlight Flaws in EU Money Laundering Rules"
    String 1 - Bitcoin ATMs Highlight Flaws in EU 
    String 2 - Money Laundering Rules

I have written below code it works for the above sample value, but it failed for 

Failed - Not returning String 1 and String 2, String is empty
string watch = " Money Laundering Rules Bitcoin ATMs Highlight Flaws in EU";
string serachetxt = "Money Laundering Rules";

This works -

List<string> matchedstr = new List<string>();
string watch = "Bitcoin ATMs Highlight Flaws in EU Money Laundering Rules";
string serachetxt = "Money Laundering Rules";

string compa = watch.Substring(0,watch.IndexOf(serachetxt)); //It returns "Bitcoin ATMs Highlight Flaws in EU"

matchedstr.Add(compa);
matchedstr.Add(serachetxt);

foreach(var itemco in matchedstr)
{

}

Upvotes: 0

Views: 148

Answers (4)

Yogesh Wavhal
Yogesh Wavhal

Reputation: 60

You can try this

        string text = "Trio charged over alleged $100m money laundering syndicate at Merrylands, Guildford West";
        string searchtext = "charged over";
        searchtextPattern =  "(?=" + searchtext + ")";

        string[] fragments= Regex.Split(text, searchtextPattern);
        //fargments will have two elements here
        // fragments[0] - "Trio"
        // fragments[1] - "charged over alleged $100m money laundering syndicate at Merrylands, Guildford West"

now you can again split fragment which have search text i.e fragments[1] in this case. see code below

            var stringWithoutSearchText = fragments[1].Replace(searchtext, string.Empty);

you need to check whether each fragment contains search text or not. You can do that it your foreach loop on fragments. add below check over there

     foreach (var item in fragments)
     { 
        if (item.Contains(searchtext))
        { 
          string stringWithoutSearchText = item.Replace(searchtext, string.Empty);
        }
     }

Reference : https://stackoverflow.com/a/521172/8652887

Upvotes: 0

Wyck
Wyck

Reputation: 11740

Use string.Split.

string text = "Bitcoin ATMs Highlight Flaws in EU Money Laundering Rules";
string searchtext = "Money Laundering Rules";
string[] fragments = text.Split(new string[] { searchtext }, StringSplitOptions.None);

fragments will equal:

[0] "Bitcoin ATMs Highlight Flaws in EU "
[1] ""

Everywhere there is a gap between consecutive array elements, your search string appears. e.g.:

string originaltext = string.Join(searchtext, fragments);

Extended Description of String.Split Behaviour

Here is a quick table of the behaviour of string.Split when passed a string.

| Input  | Split | Result Array       |
+--------+-------+--------------------+
| "ABC"  | "A"   | { "", "BC" }       |
| "ABC"  | "B"   | { "A", "C" }       |
| "ABC"  | "C"   | { "AB", "" }       |
| "ABC"  | "D"   | { "ABC" }          |
| "ABC"  | "ABC" | { "", "" }         |
| "ABBA" | "A"   | { "", "BB", "" }   |
| "ABBA" | "B"   | { "A", "", "A" }   |
| "AAA"  | "A"   | { "", "", "", "" } |
| "AAA"  | "AA"  | { "", "A" }        |

If you look at the table above, Every place there was a comma in the array (between two consecutive elements in the array), is a place that the split string was found.

If the string was not found, then the result array is only one element (the original string).

If the split string is found at the beginning of the input string, then an empty string is set as the first element of the result array to represent the beginning of the string. Similarly, if the split string is found at the end of the string, an empty string is set as the last element of the result array.

Also, an empty string is included between any consecutive occurrences of the search string in the input string.

In cases where there are ambiguous overlapping locations at which the string could be found in the input string: (e.g. splitting AAA on AA could be split as AA|A or A|AA - where AA is found at position 0 or position 1 in the input string) then the earlier location is used. (e.g. AA|A, resulting in { "", "A" } ).

Again, the invariant is that the original string can always be reconstructed by joining all the fragments and placing exactly one occurrence of the search text in between elements. The following will always be true:

string.Join(searchtext, fragments) == text

If you only want the first split...

You can merge all results after the first back together like this:

if (fragments.Length > 1) {
    fragments = new string[] { fragments[0], string.Join(searchtext, fragments.Skip(1)) };
}

... or a more efficient way using String.IndexOf

If you just want to find the first location of the search text string then use String.IndexOf to get the position of the first occurrence of the search text in the input string.

Here's a complete function you can use

private static bool TrySplitOnce(string text, string searchtext, out string beforetext, out string aftertext)
{
    int pos = text.IndexOf(searchtext);
    if (pos < 0) {
        // not found
        beforetext = null;
        aftertext = null;
        return false;
    } else {
        // found at position `pos`
        beforetext = text.Substring(0, pos); // may be ""
        aftertext = text.Substring(pos + searchtext.Length); // may be ""
        return true;
    }
}

You can use this to produce an array, if you like.

usage:

string text = "red or white or blue";
string searchtext = "or";
if (TrySplitOnce(text, searchtext, out string before, out string after)) {
    Console.WriteLine("{0}*{1}", before, after);
    // output:
    //     red * white or blue
    string[] array = new string[] { before, searchtext, after };
    // array == { "red ", "or", " white or blue" };
    Console.WriteLine(string.Join("|", array));
    // output:
    //     red |or| white or blue  
} else {
    Console.WriteLine("Not found");
}

output:

red * white or blue
red |or| white or blue

Upvotes: 0

NetMage
NetMage

Reputation: 26917

You can write your own extension method for this:

// Splits s at sep with sep included at beginning of each part except first
// return no more than numParts parts
public static IEnumerable<string> SplitsBeforeInc(this string s, string sep, int numParts = Int32.MaxValue)
    => s.Split(new[] { sep }, numParts, StringSplitOptions.None).Select((p,i) => i > 0 ? sep+p : p);

And use it with:

foreach(var itemco in watch.SplitsBeforeInc(watch, serachetxt, 2))

Here is the same method in a non-LINQ version:

// Splits s at sep with sep included at beginning of each part except first
// return no more than numParts parts
public static IEnumerable<string> SplitsBeforeInc(this string s, string sep, int numParts = Int32.MaxValue) {
    var startPos = 0;
    var searchPos = 0;
    while (startPos < s.Length && --numParts > 0) {
        var sepPos = s.IndexOf(sep, searchPos);
        sepPos = sepPos < 0 ? s.Length : sepPos;
        yield return s.Substring(startPos, sepPos - startPos);
        startPos = sepPos;
        searchPos = sepPos+sep.Length;
    }
    if (startPos < s.Length)
        yield return s.Substring(startPos);
}

Upvotes: 0

Olivier Jacot-Descombes
Olivier Jacot-Descombes

Reputation: 112352

You could just consider "Money Laundering Rules" to be the delimiter. Then you can write

string[] result = watch.Split(new string[] { searchtext }, StringSplitOptions.None);

Then you can add the delimiter again

string result1 = result[0];
string result2 = searchtext + result[1];

Upvotes: 1

Related Questions