1

I know the basics of List and IEnumerator but still I confused with this. I want to search valid URLs from a string. I can extract the valid URLs by LINQ but I would like to use IEnumerator GetEnumerator() of MatchCollection.

string url = @"http://www.ms.com http://www.hemelix.com http://www.cgi.com";
string pattern = @"http://(www\.)?([^\.]+)\.com";

List<string> result = new List<string>();
MatchCollection myMatches = Regex.Matches(url, pattern);
result = (
    from System.Text.RegularExpressions.Match m in myMatches 
    select m.Value
).ToList<string>();

var result2 = from Match m in myMatches 
              select m.Value;

foreach (var item in result2)
{
    Console.WriteLine(item.ToString());
}

// Does the following code work in this case??
result = (List<string>)myMatches.GetEnumerator();
// OR the following
IEnumerator<string> enumerator = (IEnumerator<string>) (myMatches.GetEnumerator()); 
while (enumerator.MoveNext())
{
    Console.WriteLine(enumerator.Current);
}
jeroenh
  • 26,362
  • 10
  • 73
  • 104
RotatingWheel
  • 1,023
  • 14
  • 27
  • 3
    [Freely convert between `List` and `IEnumerable`](http://stackoverflow.com/q/472669/447156)? – Soner Gönül Dec 05 '15 at 19:27
  • 1
    Have you read this? https://msdn.microsoft.com/en-us/library/b0yss765%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396 – Camilo Terevinto Dec 05 '15 at 19:27
  • 5
    In C# you rarely use IEnumerator. Typically you use IEnumerable with a foreach loop, which handles the creation and progression of the IEnumerator for you. Is there a particular reason that you want to use the enumerator manually? – Chris Shain Dec 05 '15 at 19:34

3 Answers3

3

You can't convert a List to IEnumerator, that are totally different things. The List implements IEnumerable, and Enumerator is something for iterating an IEnumerable.

Your (corrected) code

IEnumerator enumerator = myMatches.GetEnumerator();
while (enumerator.MoveNext())
{
    Console.WriteLine(enumerator.Current);
}

does the same as

foreach (var item in myMatches)
{
    Console.WriteLine(item);
}
VladL
  • 12,769
  • 10
  • 63
  • 83
  • Actually no, and worse, the latter wraps the code above in a try/finally block to call Dispose() on the enumerator in case it is disposable. – Oguz Ozgul Dec 05 '15 at 19:52
  • Thanks. is it because IEnumerator is returned from GetEnumerator() not IEnumerator? Can I get List from IEnumerator? Looks those are totally different type. – RotatingWheel Dec 05 '15 at 19:59
  • @RotatingWheel no, an Enumerator is like a pointer to the position in the List or other IEnumerable (List implements IEnumerable). It just knows there you currently are in the list. – VladL Dec 05 '15 at 20:54
  • @RotatingWheel then you call GetEnumerator() on myMatches, you will get the MatchEnumerator, which implements IEnumerator interface. If you need a List, you will have to create it first using the data contained in myMatches – VladL Dec 05 '15 at 20:57
  • @OguzOzgul not in this case, MatchEnumerator doesn't implement IDisosable – VladL Dec 05 '15 at 21:02
  • Yes. But still, for each statement will test it. that's why for each is better. If one day he uses a disposable enumerator this way, for each will dispose it automatically right after the loop – Oguz Ozgul Dec 05 '15 at 21:18
0

Here is a pretty easy way via Linq to convert your MatchCollection into a IEnumerable<string> object but this is similar to what you already did in your Linq with Query Syntax. This would just be a Method Syntax version.

IEnumerable<string> matches = myMatches.Cast<Match>().Select(m => m.Value);
foreach (var match in matches)
{
    Console.WriteLine(match);
}

Result:

http://www.ms.com
http://www.hemelix.com
http://www.cgi.com
http://www.ms.com
http://www.hemelix.com
http://www.cgi.com
Cubicle.Jockey
  • 3,288
  • 1
  • 19
  • 31
0

Primarily IEnumerable<T> operations are returned out of a method which actually would need to do it in an item by item way such as MoveNext. Frankly Regex provides a list of matches all at once; so I am not seeing the benefit of returning IEnumerable.


With that said here are two methods which achieve the same return

public static class MyOperations
{

public static string Pattern = @"https?://(www\.)?(?<Url>[^\s]+)";
public static Regex RegexHTTP = new Regex(Pattern, RegexOptions.ExplicitCapture);

public static IEnumerable<string> GetUrl(this string text)
{
    return RegexHTTP.Matches(text)
                    .OfType<Match>()
                    .Select (mt => mt.Groups["Url"].Value);
}

public static IEnumerable<string> GetUrlEx(this string text)
{
    var urls = RegexHTTP.Matches(text)
                    .OfType<Match>()
                    .Select (mt => mt.Groups["Url"].Value);

    foreach (var url in urls)
        yield return url;

}

Test Harness

string urls = "http://www.ms.com http://www.hemelix.com http://www.cgi.com http://omegacoder.com";

Console.WriteLine ("GetUrl:");
foreach (string url in urls.GetUrl())
    Console.WriteLine ("\t" + url);

Console.WriteLine ("{0}GetUrlEx:", Environment.NewLine);
foreach (string url in urls.GetUrlEx())
    Console.WriteLine ("\t" + url);

Resultant Output

GetUrl:
  ms.com
  hemelix.com
  cgi.com
  omegacoder.com

GetUrlEx:
  ms.com
  hemelix.com
  cgi.com
  omegacoder.com
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122