using System;
using System.Collections .Generic ;
using System.Linq ;
using System.Reflection ;
using System.Text .RegularExpressions ;
namespace AClient
{
public class Materiel
{
public string A { get; set; }
public int B { get; set; }
public DateTime? C { get; set; }
public string D { get; set; }
public Nested E { get; set; }
}
public struct Nested
{
public string Data { get; set; }
public override string ToString( ) { return string.Format ( "Extra: {0}" , Data) ; }
}
public static class FullText
{
public class PropMatched< T> { public PropertyInfo Property; public T Item; }
public static IEnumerable< PropMatched< T> > ByProperty< T> ( this IEnumerable< T> items, string substr)
{
return items.ByProperty ( new Regex( Regex.Escape ( substr) , RegexOptions.IgnoreCase ) ) ;
}
public static IEnumerable< PropMatched< T> > ByProperty< T> ( this IEnumerable< T> items, Regex pattern)
{
return items.Select ( i => i.MatchingProperties ( pattern) ) .Where ( m => null != m) ;
}
public static IEnumerable< T> Search< T> ( this IEnumerable< T> items, string substr)
{
return items.Search ( new Regex( Regex.Escape ( substr) , RegexOptions.IgnoreCase ) ) ;
}
public static IEnumerable< T> Search< T> ( this IEnumerable< T> items, Regex pattern)
{
return items.Where ( i => null != i.MatchingProperties ( pattern) ) ;
}
public static PropMatched< T> MatchingProperties< T> ( this T item, Regex pattern)
{
if ( null == pattern || null == item) return null ;
var properties = item.GetType ( ) .GetProperties ( BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance ) ;
var matches = from prop in properties
let val = prop.GetGetMethod ( true ) .Invoke ( item, new object[ ] { } )
where pattern.IsMatch ( ( val?? "" ) .ToString ( ) )
select prop;
var found = matches.FirstOrDefault ( ) ;
return found == null ? null : new PropMatched< T> { Item = item, Property = found} ;
}
}
class Client
{
private static readonly IEnumerable< Materiel> Database = new List< Materiel>
{
new Materiel {
A = "Hello" , B = 1 , C = null , D = "World" ,
E = new Nested { Data = "Attachment" }
} ,
new Materiel {
A = "Transfigured" , B = 2 , C = null , D = "Nights" ,
E = new Nested { Data = "Schoenberg" }
} ,
new Materiel {
A = "Moby" , B = 3 , C = null , D = "Dick" ,
E = new Nested { Data = "Biographic" }
} ,
new Materiel {
A = "Prick" , B = 4 , C = DateTime.Today , D = "World" ,
E = new Nested { Data = "Attachment" }
} ,
new Materiel {
A = "Oh Noes" , B = 2 , C = null , D = "Nights" ,
E = new Nested { Data = "Schoenberg" }
} ,
} ;
static void Main( )
{
foreach ( var pattern in new[ ] { "World" , "dick" , "Dick" , "ick" , "2012" , "Attach" } )
Console.WriteLine ( "{0} records match '{1}'" , Database.Search ( pattern) .Count ( ) , pattern) ;
// regex sample:
var regex = new Regex( @"N\w+s" , RegexOptions.IgnoreCase ) ;
Console.WriteLine ( @"{0} records match regular expression 'N\w+s'" , Database.Search ( regex) .Count ( ) ) ;
// with context info:
foreach ( var contextMatch in Database.ByProperty ( regex) )
{
Console.WriteLine ( "1 match of regex in propery {0} with value '{1}'" ,
contextMatch.Property .Name , contextMatch.Property .GetGetMethod ( ) .Invoke ( contextMatch.Item , new object[ 0 ] ) ) ;
}
}
}
}
ICAgIHVzaW5nIFN5c3RlbTsKICAgIHVzaW5nIFN5c3RlbS5Db2xsZWN0aW9ucy5HZW5lcmljOwogICAgdXNpbmcgU3lzdGVtLkxpbnE7CiAgICB1c2luZyBTeXN0ZW0uUmVmbGVjdGlvbjsKICAgIHVzaW5nIFN5c3RlbS5UZXh0LlJlZ3VsYXJFeHByZXNzaW9uczsKICAgIAogICAgbmFtZXNwYWNlIEFDbGllbnQKICAgIHsKICAgICAgICBwdWJsaWMgY2xhc3MgTWF0ZXJpZWwKICAgICAgICB7CiAgICAgICAgICAgIHB1YmxpYyBzdHJpbmcgQSB7IGdldDsgc2V0OyB9CiAgICAgICAgICAgIHB1YmxpYyBpbnQgQiB7IGdldDsgc2V0OyB9CiAgICAgICAgICAgIHB1YmxpYyBEYXRlVGltZT8gQyB7IGdldDsgc2V0OyB9CiAgICAgICAgICAgIHB1YmxpYyBzdHJpbmcgRCB7IGdldDsgc2V0OyB9CiAgICAgICAgICAgIHB1YmxpYyBOZXN0ZWQgRSB7IGdldDsgc2V0OyB9CiAgICAgICAgfQogICAgCiAgICAgICAgcHVibGljIHN0cnVjdCBOZXN0ZWQKICAgICAgICB7CiAgICAgICAgICAgIHB1YmxpYyBzdHJpbmcgRGF0YSB7IGdldDsgc2V0OyB9CiAgICAgICAgICAgIHB1YmxpYyBvdmVycmlkZSBzdHJpbmcgVG9TdHJpbmcoKSB7IHJldHVybiBzdHJpbmcuRm9ybWF0KCJFeHRyYTogezB9IiwgRGF0YSk7IH0KICAgICAgICB9CiAgICAKICAgIAogICAgICAgIHB1YmxpYyBzdGF0aWMgY2xhc3MgRnVsbFRleHQKICAgICAgICB7CiAgICAgICAgICAgIHB1YmxpYyBjbGFzcyBQcm9wTWF0Y2hlZDxUPiB7IHB1YmxpYyBQcm9wZXJ0eUluZm8gUHJvcGVydHk7IHB1YmxpYyBUIEl0ZW07IH0KICAgIAogICAgICAgICAgICBwdWJsaWMgc3RhdGljIElFbnVtZXJhYmxlPFByb3BNYXRjaGVkPFQ+ID4gQnlQcm9wZXJ0eTxUPih0aGlzIElFbnVtZXJhYmxlPFQ+IGl0ZW1zLCBzdHJpbmcgc3Vic3RyKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICByZXR1cm4gaXRlbXMuQnlQcm9wZXJ0eShuZXcgUmVnZXgoUmVnZXguRXNjYXBlKHN1YnN0ciksIFJlZ2V4T3B0aW9ucy5JZ25vcmVDYXNlKSk7CiAgICAgICAgICAgIH0KICAgIAogICAgICAgICAgICBwdWJsaWMgc3RhdGljIElFbnVtZXJhYmxlPFByb3BNYXRjaGVkPFQ+ID4gQnlQcm9wZXJ0eTxUPih0aGlzIElFbnVtZXJhYmxlPFQ+IGl0ZW1zLCBSZWdleCBwYXR0ZXJuKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICByZXR1cm4gaXRlbXMuU2VsZWN0KGkgPT4gaS5NYXRjaGluZ1Byb3BlcnRpZXMocGF0dGVybikpLldoZXJlKG0gPT4gbnVsbCAhPSBtKTsKICAgICAgICAgICAgfQogICAgCiAgICAgICAgICAgIHB1YmxpYyBzdGF0aWMgSUVudW1lcmFibGU8VD4gU2VhcmNoPFQ+KHRoaXMgSUVudW1lcmFibGU8VD4gaXRlbXMsIHN0cmluZyBzdWJzdHIpCiAgICAgICAgICAgIHsKICAgICAgICAgICAgICAgIHJldHVybiBpdGVtcy5TZWFyY2gobmV3IFJlZ2V4KFJlZ2V4LkVzY2FwZShzdWJzdHIpLCBSZWdleE9wdGlvbnMuSWdub3JlQ2FzZSkpOwogICAgICAgICAgICB9CiAgICAKICAgICAgICAgICAgcHVibGljIHN0YXRpYyBJRW51bWVyYWJsZTxUPiBTZWFyY2g8VD4odGhpcyBJRW51bWVyYWJsZTxUPiBpdGVtcywgUmVnZXggcGF0dGVybikKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgcmV0dXJuIGl0ZW1zLldoZXJlKGkgPT4gbnVsbCAhPSBpLk1hdGNoaW5nUHJvcGVydGllcyhwYXR0ZXJuKSk7CiAgICAgICAgICAgIH0KICAgIAogICAgICAgICAgICBwdWJsaWMgc3RhdGljIFByb3BNYXRjaGVkPFQ+IE1hdGNoaW5nUHJvcGVydGllczxUPih0aGlzIFQgaXRlbSwgUmVnZXggcGF0dGVybikKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgaWYgKG51bGwgPT0gcGF0dGVybiB8fCBudWxsID09IGl0ZW0pIHJldHVybiBudWxsOwogICAgCiAgICAgICAgICAgICAgICB2YXIgcHJvcGVydGllcyA9IGl0ZW0uR2V0VHlwZSgpLkdldFByb3BlcnRpZXMoQmluZGluZ0ZsYWdzLlB1YmxpYyB8IEJpbmRpbmdGbGFncy5GbGF0dGVuSGllcmFyY2h5IHwgQmluZGluZ0ZsYWdzLkluc3RhbmNlKTsKICAgICAgICAgICAgICAgIHZhciBtYXRjaGVzID0gZnJvbSAgIHByb3AgaW4gcHJvcGVydGllcyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV0ICAgIHZhbCA9IHByb3AuR2V0R2V0TWV0aG9kKHRydWUpLkludm9rZShpdGVtLCBuZXcgb2JqZWN0W117fSkgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoZXJlICBwYXR0ZXJuLklzTWF0Y2goKHZhbD8/IiIpLlRvU3RyaW5nKCkpIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QgcHJvcDsKICAgIAogICAgICAgICAgICAgICAgdmFyIGZvdW5kID0gbWF0Y2hlcy5GaXJzdE9yRGVmYXVsdCgpOwogICAgICAgICAgICAgICAgcmV0dXJuIGZvdW5kID09IG51bGwgPyBudWxsIDogbmV3IFByb3BNYXRjaGVkPFQ+IHtJdGVtID0gaXRlbSwgUHJvcGVydHkgPSBmb3VuZH07CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAKICAgICAgICBjbGFzcyBDbGllbnQKICAgICAgICB7CiAgICAgICAgICAgIHByaXZhdGUgc3RhdGljIHJlYWRvbmx5IElFbnVtZXJhYmxlPE1hdGVyaWVsPiBEYXRhYmFzZSA9IG5ldyBMaXN0PE1hdGVyaWVsPgogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIG5ldyBNYXRlcmllbCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBBID0gIkhlbGxvIiwgQiA9IDEsIEMgPSBudWxsLCBEID0gIldvcmxkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEUgPSBuZXcgTmVzdGVkIHtEYXRhID0gIkF0dGFjaG1lbnQifQogICAgICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAgIG5ldyBNYXRlcmllbCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBBID0gIlRyYW5zZmlndXJlZCIsIEIgPSAyLCBDID0gbnVsbCwgRCA9ICJOaWdodHMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgRSA9IG5ldyBOZXN0ZWQge0RhdGEgPSAiU2Nob2VuYmVyZyJ9CiAgICAgICAgICAgICAgICAgICAgICAgIH0sCiAgICAgICAgICAgICAgICAgICAgbmV3IE1hdGVyaWVsIHsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEEgPSAiTW9ieSIsIEIgPSAzLCBDID0gbnVsbCwgRCA9ICJEaWNrIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIEUgPSBuZXcgTmVzdGVkIHtEYXRhID0gIkJpb2dyYXBoaWMifQogICAgICAgICAgICAgICAgICAgICAgICB9LAogICAgICAgICAgICAgICAgICAgIG5ldyBNYXRlcmllbCB7CiAgICAgICAgICAgICAgICAgICAgICAgICAgICBBID0gIlByaWNrIiwgQiA9IDQsIEMgPSBEYXRlVGltZS5Ub2RheSwgRCA9ICJXb3JsZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBFID0gbmV3IE5lc3RlZCB7RGF0YSA9ICJBdHRhY2htZW50In0KICAgICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgICAgICBuZXcgTWF0ZXJpZWwgewogICAgICAgICAgICAgICAgICAgICAgICAgICAgQSA9ICJPaCBOb2VzIiwgQiA9IDIsIEMgPSBudWxsLCBEID0gIk5pZ2h0cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBFID0gbmV3IE5lc3RlZCB7RGF0YSA9ICJTY2hvZW5iZXJnIn0KICAgICAgICAgICAgICAgICAgICAgICAgfSwKICAgICAgICAgICAgICAgIH07CiAgICAKICAgIAogICAgICAgICAgICBzdGF0aWMgdm9pZCBNYWluKCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgZm9yZWFjaCAodmFyIHBhdHRlcm4gaW4gbmV3W117ICJXb3JsZCIgLCAiZGljayIsICJEaWNrIiwgImljayIsICIyMDEyIiwgIkF0dGFjaCIgfSkKICAgICAgICAgICAgICAgICAgICBDb25zb2xlLldyaXRlTGluZSgiezB9IHJlY29yZHMgbWF0Y2ggJ3sxfSciLCBEYXRhYmFzZS5TZWFyY2gocGF0dGVybikuQ291bnQoKSwgcGF0dGVybik7CiAgICAKICAgICAgICAgICAgICAgIC8vIHJlZ2V4IHNhbXBsZToKICAgICAgICAgICAgICAgIHZhciByZWdleCA9IG5ldyBSZWdleChAIk5cdytzIiwgUmVnZXhPcHRpb25zLklnbm9yZUNhc2UpOwogICAgCiAgICAgICAgICAgICAgICBDb25zb2xlLldyaXRlTGluZShAInswfSByZWNvcmRzIG1hdGNoIHJlZ3VsYXIgZXhwcmVzc2lvbiAnTlx3K3MnIiwgRGF0YWJhc2UuU2VhcmNoKHJlZ2V4KS5Db3VudCgpKTsKICAgIAogICAgICAgICAgICAgICAgLy8gd2l0aCBjb250ZXh0IGluZm86CiAgICAgICAgICAgICAgICBmb3JlYWNoICh2YXIgY29udGV4dE1hdGNoIGluIERhdGFiYXNlLkJ5UHJvcGVydHkocmVnZXgpKQogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgIENvbnNvbGUuV3JpdGVMaW5lKCIxIG1hdGNoIG9mIHJlZ2V4IGluIHByb3BlcnkgezB9IHdpdGggdmFsdWUgJ3sxfSciLAogICAgICAgICAgICAgICAgICAgICAgICBjb250ZXh0TWF0Y2guUHJvcGVydHkuTmFtZSwgY29udGV4dE1hdGNoLlByb3BlcnR5LkdldEdldE1ldGhvZCgpLkludm9rZShjb250ZXh0TWF0Y2guSXRlbSwgbmV3IG9iamVjdFswXSkpOwogICAgCiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICB9CgoK