Megosztás a következőn keresztül:


Útmutató: Sztringek lekérdezése a LINQ használatával

A sztringek karaktersorozatként vannak tárolva. Karaktersorozatként a LINQ használatával kérdezhetők le. Ebben a cikkben számos példa lekérdezés található, amelyek különböző karaktereket vagy szavakat kérdeznek le, sztringeket szűrnek, vagy a lekérdezéseket normál kifejezésekkel keverik.

Karakterlánc karaktereinek lekérdezése

Az alábbi példa lekérdez egy sztringet a benne található numerikus számjegyek számának meghatározásához.

string aString = "ABCDE99F-J74-12-89A";

// Select only those characters that are numbers
var stringQuery = from ch in aString
                  where Char.IsDigit(ch)
                  select ch;

// Execute the query
foreach (char c in stringQuery)
    Console.Write(c + " ");

// Call the Count method on the existing query.
int count = stringQuery.Count();
Console.WriteLine($"Count = {count}");

// Select all characters before the first '-'
var stringQuery2 = aString.TakeWhile(c => c != '-');

// Execute the second query
foreach (char c in stringQuery2)
    Console.Write(c);
/* Output:
  Output: 9 9 7 4 1 2 8 9
  Count = 8
  ABCDE99F
*/

Az előző lekérdezés bemutatja, hogyan kezelheti a sztringeket karaktersorozatként.

Szó előfordulásainak megszámlálása sztringben

Az alábbi példa bemutatja, hogyan használható LINQ-lekérdezés egy adott szó előfordulásainak megszámlálására egy sztringben. A szám végrehajtásához először a Split metódust hívjuk meg szavak tömbjének létrehozásához. A metódusnak teljesítményköltsége Split van. Ha a sztring egyetlen művelete a szavak megszámlálása, fontolja meg inkább a Matches metódusok használatát IndexOf .

string text = """
    Historically, the world of data and the world of objects 
    have not been well integrated. Programmers work in C# or Visual Basic 
    and also in SQL or XQuery. On the one side are concepts such as classes, 
    objects, fields, inheritance, and .NET APIs. On the other side 
    are tables, columns, rows, nodes, and separate languages for dealing with 
    them. Data types often require translation between the two worlds; there are 
    different standard functions. Because the object world has no notion of query, a 
    query can only be represented as a string without compile-time type checking or 
    IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to 
    objects in memory is often tedious and error-prone. 
    """;

string searchTerm = "data";

//Convert the string into an array of words
char[] separators = ['.', '?', '!', ' ', ';', ':', ','];
string[] source = text.Split(separators, StringSplitOptions.RemoveEmptyEntries);

// Create the query.  Use the InvariantCultureIgnoreCase comparison to match "data" and "Data"
var matchQuery = from word in source
                 where word.Equals(searchTerm, StringComparison.InvariantCultureIgnoreCase)
                 select word;

// Count the matches, which executes the query.
int wordCount = matchQuery.Count();
Console.WriteLine($"""{wordCount} occurrences(s) of the search term "{searchTerm}" were found.""");
/* Output:
   3 occurrences(s) of the search term "data" were found.
*/

Az előző lekérdezés bemutatja, hogyan tekintheti meg a sztringeket szavak sorozataként, miután egy sztringet szavak sorozatára osztott.

Szövegadatok rendezése vagy szűrése bármely szó vagy mező alapján

Az alábbi példa bemutatja, hogyan rendezhet strukturált szövegsorokat, például vesszővel tagolt értékeket a sor bármely mezőjével. A mező futásidőben dinamikusan megadható. Tegyük fel, hogy a scores.csv mezői egy tanuló azonosítószámát jelölik, amelyet négy tesztpontszám követ:

111, 97, 92, 81, 60
112, 75, 84, 91, 39
113, 88, 94, 65, 91
114, 97, 89, 85, 82
115, 35, 72, 91, 70
116, 99, 86, 90, 94
117, 93, 92, 80, 87
118, 92, 90, 83, 78
119, 68, 79, 88, 92
120, 99, 82, 81, 79
121, 96, 85, 91, 60
122, 94, 92, 91, 91

A következő lekérdezés a sorokat az első vizsga pontszáma alapján rendezi, amely a második oszlopban van tárolva:

// Create an IEnumerable data source
string[] scores = File.ReadAllLines("scores.csv");

// Change this to any value from 0 to 4.
int sortField = 1;

Console.WriteLine($"Sorted highest to lowest by field [{sortField}]:");

// Split the string and sort on field[num]
var scoreQuery = from line in scores
                 let fields = line.Split(',')
                 orderby fields[sortField] descending
                 select line;

foreach (string str in scoreQuery)
{
    Console.WriteLine(str);
}
/* Output (if sortField == 1):
   Sorted highest to lowest by field [1]:
    116, 99, 86, 90, 94
    120, 99, 82, 81, 79
    111, 97, 92, 81, 60
    114, 97, 89, 85, 82
    121, 96, 85, 91, 60
    122, 94, 92, 91, 91
    117, 93, 92, 80, 87
    118, 92, 90, 83, 78
    113, 88, 94, 65, 91
    112, 75, 84, 91, 39
    119, 68, 79, 88, 92
    115, 35, 72, 91, 70
 */

Az előző lekérdezés bemutatja, hogyan módosíthatja a sztringeket úgy, hogy mezőkre osztja őket, és lekérdezi az egyes mezőket.

Mondatok lekérdezése adott szavakkal

Az alábbi példa bemutatja, hogyan kereshet mondatokat olyan szövegfájlban, amely az egyes szavakra vonatkozó egyezéseket tartalmaz. Bár a keresési kifejezések tömbje keményen kódolt, futtatáskor dinamikusan is feltölthető. A lekérdezés azokat a mondatokat adja vissza, amelyek a "Történelmileg", az "adatok" és az "integrált" szavakat tartalmazzák.

string text = """
Historically, the world of data and the world of objects 
have not been well integrated. Programmers work in C# or Visual Basic 
and also in SQL or XQuery. On the one side are concepts such as classes, 
objects, fields, inheritance, and .NET APIs. On the other side 
are tables, columns, rows, nodes, and separate languages for dealing with 
them. Data types often require translation between the two worlds; there are 
different standard functions. Because the object world has no notion of query, a 
query can only be represented as a string without compile-time type checking or 
IntelliSense support in the IDE. Transferring data from SQL tables or XML trees to 
objects in memory is often tedious and error-prone.
""";

// Split the text block into an array of sentences.
string[] sentences = text.Split(['.', '?', '!']);

// Define the search terms. This list could also be dynamically populated at run time.
string[] wordsToMatch = [ "Historically", "data", "integrated" ];

// Find sentences that contain all the terms in the wordsToMatch array.
// Note that the number of terms to match is not specified at compile time.
char[] separators = ['.', '?', '!', ' ', ';', ':', ','];
var sentenceQuery = from sentence in sentences
                    let w = sentence.Split(separators,StringSplitOptions.RemoveEmptyEntries)
                    where w.Distinct().Intersect(wordsToMatch).Count() == wordsToMatch.Count()
                    select sentence;

foreach (string str in sentenceQuery)
{
    Console.WriteLine(str);
}
/* Output:
Historically, the world of data and the world of objects have not been well integrated
*/

A lekérdezés először mondatokra osztja a szöveget, majd az egyes mondatokat az egyes szavakat tartalmazó sztringek tömbjeire osztja. Mindegyik tömb esetében a metódus eltávolítja az Distinct összes ismétlődő szót, majd a lekérdezés végrehajt egy Intersect műveletet a szótömbön és a wordsToMatch tömbön. Ha a metszet száma megegyezik a wordsToMatch tömb számával, az összes szó megtalálható a szavakban, és a rendszer visszaadja az eredeti mondatot.

A hívás írásjeleket Split használ elválasztóként, hogy eltávolítsa őket a sztringből. Ha nem távolítja el az írásjeleket, például rendelkezhet egy "Történelmi" sztringgel, amely nem felelne meg a "Történelmileg" kifejezésnek a wordsToMatch tömbben. Előfordulhat, hogy a forrásszövegben található írásjelek típusától függően további elválasztójeleket kell használnia.

LINQ-lekérdezések kombinálása reguláris kifejezésekkel

Az alábbi példa bemutatja, hogyan hozhat létre normál kifejezést az Regex osztály használatával a szöveges sztringek összetettebb egyeztetéséhez. A LINQ-lekérdezéssel egyszerűen szűrheti pontosan a normál kifejezéssel keresni kívánt fájlokat, és formázhatja az eredményeket.

string startFolder = """C:\Program Files\dotnet\sdk""";
// Or
// string startFolder = "/usr/local/share/dotnet/sdk";

// Take a snapshot of the file system.
var fileList = from file in Directory.GetFiles(startFolder, "*.*", SearchOption.AllDirectories)
                let fileInfo = new FileInfo(file)
                select fileInfo;

// Create the regular expression to find all things "Visual".
System.Text.RegularExpressions.Regex searchTerm =
    new System.Text.RegularExpressions.Regex(@"microsoft.net.(sdk|workload)");

// Search the contents of each .htm file.
// Remove the where clause to find even more matchedValues!
// This query produces a list of files where a match
// was found, and a list of the matchedValues in that file.
// Note: Explicit typing of "Match" in select clause.
// This is required because MatchCollection is not a
// generic IEnumerable collection.
var queryMatchingFiles =
    from file in fileList
    where file.Extension == ".txt"
    let fileText = File.ReadAllText(file.FullName)
    let matches = searchTerm.Matches(fileText)
    where matches.Count > 0
    select new
    {
        name = file.FullName,
        matchedValues = from System.Text.RegularExpressions.Match match in matches
                        select match.Value
    };

// Execute the query.
Console.WriteLine($"""The term "{searchTerm}" was found in:""");

foreach (var v in queryMatchingFiles)
{
    // Trim the path a bit, then write
    // the file name in which a match was found.
    string s = v.name.Substring(startFolder.Length - 1);
    Console.WriteLine(s);

    // For this file, write out all the matching strings
    foreach (var v2 in v.matchedValues)
    {
        Console.WriteLine($"  {v2}");
    }
}

A keresés által RegEx visszaadott objektumot is lekérdezhetiMatchCollection. Az eredményekben csak az egyes egyezések értéke jön létre. A LINQ használatával azonban bármilyen szűrést, rendezést és csoportosítást végezhet a gyűjteményen. Mivel MatchCollection nemgenerikus IEnumerable gyűjteményről van szó, explicit módon meg kell adnia a tartományváltozó típusát a lekérdezésben.