Skip to content

Commit cd83afc

Browse files
authored
Init
0 parents  commit cd83afc

File tree

6 files changed

+806
-0
lines changed

6 files changed

+806
-0
lines changed

LICENSE

Lines changed: 661 additions & 0 deletions
Large diffs are not rendered by default.

LinkSolver.csproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net7.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
</Project>

LinkSolver.sln

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.5.33103.201
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinkSolver", "LinkSolver.csproj", "{40DC2B3D-2B18-4305-9DBB-AFCFDAAE415C}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{40DC2B3D-2B18-4305-9DBB-AFCFDAAE415C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{40DC2B3D-2B18-4305-9DBB-AFCFDAAE415C}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{40DC2B3D-2B18-4305-9DBB-AFCFDAAE415C}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{40DC2B3D-2B18-4305-9DBB-AFCFDAAE415C}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {051E4911-73FB-4DB1-8BD6-7E0C5DAED167}
24+
EndGlobalSection
25+
EndGlobal

Program.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using LinkSolver;
2+
3+
namespace WikiLinkSolver {
4+
public class Program {
5+
public static async Task Main() {
6+
string firstDefinition = "Börek";
7+
string searchedDefinition = "Midnight";
8+
9+
var wikiSolver = new WikiSolver(2);
10+
11+
await wikiSolver.Run(firstDefinition, searchedDefinition);
12+
}
13+
}
14+
}

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Wikipedia Link Solver<br>
2+
You create an instance of the object 'WikiSolver' with optinal depth of links to enter until get result in the constructor (default is 3)<br>
3+
You Run with function you run with 2 parameter, starting page and target page.<br>
4+
In run also third parameter, choose language of the pages you want to search on, default is 'en'.<br>

WikiSolver.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using System.Text.RegularExpressions;
2+
3+
namespace LinkSolver {
4+
public record struct Node(string Value, int Depth, List<string> Path);
5+
6+
public partial class WikiSolver {
7+
private const string WIKI = "/wiki/";
8+
private const string WIKI_URL_FORMAT = "https://{0}.wikipedia.org/wiki/";
9+
10+
private readonly Regex _regex = MyRegex();
11+
private string? _wikiUrl = string.Empty;
12+
13+
public uint MaximumDepth;
14+
15+
public WikiSolver(uint maxDepth = 3) {
16+
MaximumDepth = maxDepth;
17+
}
18+
19+
public async Task Run(string start, string target, string language = "en") {
20+
if (start == null || start.Length == 0 || target == null || target.Length == 0) {
21+
return;
22+
}
23+
24+
_wikiUrl = string.Format(WIKI_URL_FORMAT, language);
25+
Console.WriteLine(_wikiUrl);
26+
27+
var queue = new Queue<Node>();
28+
queue.Enqueue(new Node(start, 0, new List<string>() { start }));
29+
30+
var found = await IterateOnQueue(queue, target);
31+
PrintResult(found);
32+
}
33+
34+
private async Task<Node> IterateOnQueue(Queue<Node> queue, string target) {
35+
Node found = default;
36+
var client = new HttpClient();
37+
38+
while (found == default && queue.Any()) {
39+
var current = queue.Dequeue();
40+
41+
Console.WriteLine($"Working on {current.Value} in depth {current.Depth}");
42+
43+
if (current.Depth == MaximumDepth) {
44+
continue;
45+
}
46+
47+
var wikiPage = await GetWikiPage(client, current.Value);
48+
found = RunOnLinks(wikiPage, target, current, queue);
49+
};
50+
51+
return found;
52+
}
53+
54+
private async Task<string> GetWikiPage(HttpClient client, string page) {
55+
var response = await client.GetAsync($"{_wikiUrl}{page}");
56+
return await response.Content.ReadAsStringAsync();
57+
}
58+
59+
private Node RunOnLinks(string wikiPage, string target, Node current, Queue<Node> queue) {
60+
foreach (var match in _regex.Matches(wikiPage).ToHashSet<Match>()) {
61+
var value = match.Groups[1].ToString();
62+
63+
if (!value.StartsWith(WIKI) || value.Contains('.') || value.Contains(':')) {
64+
continue;
65+
}
66+
67+
value = value.Replace(WIKI, "", StringComparison.OrdinalIgnoreCase);
68+
69+
if (value == target) {
70+
current.Path.Add(value);
71+
return current;
72+
}
73+
74+
var list = new List<string>(current.Path) { value };
75+
queue.Enqueue(new Node(value, current.Depth + 1, list));
76+
}
77+
78+
return default;
79+
}
80+
81+
private static void PrintResult(Node result) {
82+
var isFound = result != default;
83+
Console.WriteLine("Result is: " + (isFound ? "Found" : "Can\'t link"));
84+
if (isFound) {
85+
Console.WriteLine($"The path is: {string.Join(" -> ", result.Path)}");
86+
}
87+
}
88+
89+
[GeneratedRegex("href=\"(.*?)\"")]
90+
private static partial Regex MyRegex();
91+
}
92+
}

0 commit comments

Comments
 (0)