Initial commit

This commit is contained in:
Mark J Price 2022-03-02 08:51:03 +00:00
parent c0d4d11b54
commit 0e89590d92
46 changed files with 1741 additions and 0 deletions

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,24 @@
using System.Text.RegularExpressions;
WriteLine("The default regular expression checks for at least one digit.");
do
{
Write("Enter a regular expression (or press ENTER to use the default): ");
string? regexp = ReadLine();
if (string.IsNullOrWhiteSpace(regexp))
{
regexp = @"^\d+$";
}
Write("Enter some input: ");
string input = ReadLine()!; // will never be null
Regex r = new(regexp);
WriteLine($"{input} matches {regexp}: {r.IsMatch(input)}");
WriteLine("Press ESC to end or any key to try again.");
}
while (ReadKey(intercept: true).Key != ConsoleKey.Escape);

View file

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ch08Ex03NumbersAsWordsLib\Ch08Ex03NumbersAsWordsLib.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,16 @@
using Packt.Shared; // ToWords extension method
using System.Numerics; // BigInteger
Write("Enter a number up to twenty one digits long: ");
string? input = ReadLine();
if (input is null) return;
if (input.Length > 21)
{
WriteLine("I cannot handle more than twenty one digits!");
return;
}
BigInteger number = BigInteger.Parse(input);
WriteLine($"{number:N0} in words is {number.ToWords()}.");

View file

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,220 @@
using System.Diagnostics; // Trace
using System.IO; // File
using System.Numerics; // BigInteger
namespace Packt.Shared
{
public static class NumbersToWords
{
// Single-digit and small number names
private static string[] smallNumbers = new string[]
{
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen"
};
// Tens number names from twenty upwards
private static string[] tens = new string[]
{
"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy",
"eighty", "ninety"
};
// Scale number names for use during recombination
private static string[] scaleNumbers = new string[]
{
"", "thousand", "million", "billion", "trillion",
"quadrillion", "quintillion"
};
private static int groups = 7; // i.e. up to quintillion
public static string ToWords(this int number)
{
return ToWords((BigInteger)number);
}
public static string ToWords(this long number)
{
return ToWords((BigInteger)number);
}
public static string ToWords(this BigInteger number)
{
/*
Convert A Number into Words
by Richard Carr, published at http://www.blackwasp.co.uk/numbertowords.aspx
*/
/*
Zero Rule.
If the value is 0 then the number in words is 'zero' and no other rules apply.
*/
if (number == 0)
{
return "zero";
}
/*
Three Digit Rule.
The integer value is split into groups of three digits starting from the
right-hand side. Each set of three digits is then processed individually
as a number of hundreds, tens and units. Once converted to text, the
three-digit groups are recombined with the addition of the relevant scale
number (thousand, million, billion).
*/
// Array to hold the specified number of three-digit groups
int[] digitGroups = new int[groups];
// Ensure a positive number to extract from
var positive = BigInteger.Abs(number);
// Extract the three-digit groups
for (int i = 0; i < groups; i++)
{
digitGroups[i] = (int)(positive % 1000);
positive /= 1000;
}
// write to a text file in the project folder
Trace.Listeners.Add(new TextWriterTraceListener(
File.AppendText("log.txt")));
// text writer is buffered, so this option calls
// Flush() on all listeners after writing
Trace.AutoFlush = true;
// log array of group numbers
for (int x = 0; x < digitGroups.Length; x++)
{
Trace.WriteLine(string.Format(
format: "digitGroups[{0}] = {1}",
arg0: x,
arg1: digitGroups[x]));
}
// Convert each three-digit group to words
string[] groupTexts = new string[groups];
for (int i = 0; i < groups; i++)
{
// call a local function (see below)
groupTexts[i] = ThreeDigitGroupToWords(digitGroups[i]);
}
// log array of group texts
for (int x = 0; x < groupTexts.Length; x++)
{
Trace.WriteLine(string.Format(
format: "groupTexts[{0}] = {1}",
arg0: x,
arg1: groupTexts[x]));
}
/*
Recombination Rules.
When recombining the translated three-digit groups, each group except the
last is followed by a large number name and a comma, unless the group is
blank and therefore not included at all. One exception is when the final
group does not include any hundreds and there is more than one non-blank
group. In this case, the final comma is replaced with 'and'. eg.
'one billion, one million and twelve'.
*/
// Recombine the three-digit groups
string combined = groupTexts[0];
bool appendAnd;
// Determine whether an 'and' is needed
appendAnd = (digitGroups[0] > 0) && (digitGroups[0] < 100);
// Process the remaining groups in turn, smallest to largest
for (int i = 1; i < groups; i++)
{
// Only add non-zero items
if (digitGroups[i] != 0)
{
// Build the string to add as a prefix
string prefix = groupTexts[i] + " " + scaleNumbers[i];
if (combined.Length != 0)
{
prefix += appendAnd ? " and " : ", ";
}
// Opportunity to add 'and' is ended
appendAnd = false;
// Add the three-digit group to the combined string
combined = prefix + combined;
}
}
// Converts a three-digit group into English words
string ThreeDigitGroupToWords(int threeDigits)
{
// Initialise the return text
string groupText = "";
// Determine the hundreds and the remainder
int hundreds = threeDigits / 100;
int tensUnits = threeDigits % 100;
/*
Hundreds Rules.
If the hundreds portion of a three-digit group is not zero, the number of
hundreds is added as a word. If the three-digit group is exactly divisible
by one hundred, the text 'hundred' is appended. If not, the text
"hundred and" is appended. eg. 'two hundred' or 'one hundred and twelve'
*/
if (hundreds != 0)
{
groupText += smallNumbers[hundreds] + " hundred";
if (tensUnits != 0)
{
groupText += " and ";
}
}
// Determine the tens and units
int tens = tensUnits / 10;
int units = tensUnits % 10;
/* Tens Rules.
If the tens section of a three-digit group is two or higher, the appropriate
'-ty' word (twenty, thirty, etc.) is added to the text and followed by the
name of the third digit (unless the third digit is a zero, which is ignored).
If the tens and the units are both zero, no text is added. For any other value,
the name of the one or two-digit number is added as a special case.
*/
if (tens >= 2)
{
groupText += NumbersToWords.tens[tens];
if (units != 0)
{
groupText += " " + smallNumbers[units];
}
}
else if (tensUnits != 0)
groupText += smallNumbers[tensUnits];
return groupText;
}
/* Negative Rule.
Negative numbers are always preceded by the text 'negative'.
*/
if (number < 0)
{
combined = "negative " + combined;
}
return combined;
}
}
}

View file

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Ch08Ex03NumbersAsWordsLib\Ch08Ex03NumbersAsWordsLib.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,64 @@
using Packt.Shared; // ToWords extension method
using System.Numerics; // BigInteger
namespace Ch08Ex03NumbersAsWordsTests
{
public class NumbersToWordsUnitTests
{
[Fact]
public void Test_Int32_0()
{
// arrange
int number = 0;
string expected = "zero";
// act
string actual = number.ToWords();
// assert
Assert.Equal(expected, actual);
}
[Fact]
public void Test_Int32_1234()
{
// arrange
int number = 1234;
string expected = "one thousand, two hundred and thirty four";
// act
string actual = number.ToWords();
// assert
Assert.Equal(expected, actual);
}
[Fact]
public void Test_BigInteger_18456002032011000007()
{
// arrange
BigInteger number = BigInteger.Parse("18456002032011000007");
string expected = "eighteen quintillion, four hundred and fifty six quadrillion, two trillion, thirty two billion, eleven million and seven";
// act
string actual = number.ToWords();
// assert
Assert.Equal(expected, actual);
}
[Fact]
public void Test_Int32_minus_13()
{
// arrange
int number = -13;
string expected = "negative thirteen";
// act
string actual = number.ToWords();
// assert
Assert.Equal(expected, actual);
}
}
}

View file

@ -0,0 +1 @@
global using Xunit;

View file

@ -0,0 +1,79 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32210.308
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkingWithNumbers", "WorkingWithNumbers\WorkingWithNumbers.csproj", "{EF42A2EE-FB4A-4BE4-A331-2B3D6CC1A1C5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkingWithText", "WorkingWithText\WorkingWithText.csproj", "{BD0568D2-A0C9-4FB5-AD3A-A685E794A29E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkingWithRegularExpressions", "WorkingWithRegularExpressions\WorkingWithRegularExpressions.csproj", "{221EF67C-EB18-417F-811F-2836BBC4B9ED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkingWithCollections", "WorkingWithCollections\WorkingWithCollections.csproj", "{678CA866-8E00-48EB-A8F5-1D587BFB311A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkingWithRanges", "WorkingWithRanges\WorkingWithRanges.csproj", "{D93AB524-D62D-422B-895A-B1F0ACD3E137}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkingWithNetworkResources", "WorkingWithNetworkResources\WorkingWithNetworkResources.csproj", "{5A9BBCB8-F680-45DA-BBAD-DC20F3FBEE4E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ch08Ex02RegularExpressions", "Ch08Ex02RegularExpressions\Ch08Ex02RegularExpressions.csproj", "{BDCF7297-FA66-437C-A428-AF1B32C520DD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ch08Ex03NumbersAsWordsLib", "Ch08Ex03NumbersAsWordsLib\Ch08Ex03NumbersAsWordsLib.csproj", "{42F893F1-B861-4B4B-A14B-4F278E11F87F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ch08Ex03NumbersAsWordsApp", "Ch08Ex03NumbersAsWordsApp\Ch08Ex03NumbersAsWordsApp.csproj", "{25385931-197B-4713-82B9-74764DBD76A3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ch08Ex03NumbersAsWordsTests", "Ch08Ex03NumbersAsWordsTests\Ch08Ex03NumbersAsWordsTests.csproj", "{793E6479-9AE4-4802-B5BF-BC4CED5E72F0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EF42A2EE-FB4A-4BE4-A331-2B3D6CC1A1C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EF42A2EE-FB4A-4BE4-A331-2B3D6CC1A1C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EF42A2EE-FB4A-4BE4-A331-2B3D6CC1A1C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EF42A2EE-FB4A-4BE4-A331-2B3D6CC1A1C5}.Release|Any CPU.Build.0 = Release|Any CPU
{BD0568D2-A0C9-4FB5-AD3A-A685E794A29E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD0568D2-A0C9-4FB5-AD3A-A685E794A29E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD0568D2-A0C9-4FB5-AD3A-A685E794A29E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD0568D2-A0C9-4FB5-AD3A-A685E794A29E}.Release|Any CPU.Build.0 = Release|Any CPU
{221EF67C-EB18-417F-811F-2836BBC4B9ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{221EF67C-EB18-417F-811F-2836BBC4B9ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{221EF67C-EB18-417F-811F-2836BBC4B9ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{221EF67C-EB18-417F-811F-2836BBC4B9ED}.Release|Any CPU.Build.0 = Release|Any CPU
{678CA866-8E00-48EB-A8F5-1D587BFB311A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{678CA866-8E00-48EB-A8F5-1D587BFB311A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{678CA866-8E00-48EB-A8F5-1D587BFB311A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{678CA866-8E00-48EB-A8F5-1D587BFB311A}.Release|Any CPU.Build.0 = Release|Any CPU
{D93AB524-D62D-422B-895A-B1F0ACD3E137}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D93AB524-D62D-422B-895A-B1F0ACD3E137}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D93AB524-D62D-422B-895A-B1F0ACD3E137}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D93AB524-D62D-422B-895A-B1F0ACD3E137}.Release|Any CPU.Build.0 = Release|Any CPU
{5A9BBCB8-F680-45DA-BBAD-DC20F3FBEE4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5A9BBCB8-F680-45DA-BBAD-DC20F3FBEE4E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5A9BBCB8-F680-45DA-BBAD-DC20F3FBEE4E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5A9BBCB8-F680-45DA-BBAD-DC20F3FBEE4E}.Release|Any CPU.Build.0 = Release|Any CPU
{BDCF7297-FA66-437C-A428-AF1B32C520DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BDCF7297-FA66-437C-A428-AF1B32C520DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDCF7297-FA66-437C-A428-AF1B32C520DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDCF7297-FA66-437C-A428-AF1B32C520DD}.Release|Any CPU.Build.0 = Release|Any CPU
{42F893F1-B861-4B4B-A14B-4F278E11F87F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{42F893F1-B861-4B4B-A14B-4F278E11F87F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42F893F1-B861-4B4B-A14B-4F278E11F87F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{42F893F1-B861-4B4B-A14B-4F278E11F87F}.Release|Any CPU.Build.0 = Release|Any CPU
{25385931-197B-4713-82B9-74764DBD76A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{25385931-197B-4713-82B9-74764DBD76A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25385931-197B-4713-82B9-74764DBD76A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25385931-197B-4713-82B9-74764DBD76A3}.Release|Any CPU.Build.0 = Release|Any CPU
{793E6479-9AE4-4802-B5BF-BC4CED5E72F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{793E6479-9AE4-4802-B5BF-BC4CED5E72F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{793E6479-9AE4-4802-B5BF-BC4CED5E72F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{793E6479-9AE4-4802-B5BF-BC4CED5E72F0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BD4295A9-D6CF-470E-8220-CDA9A1FEA2C6}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,21 @@
partial class Program
{
static void Output(string title, IEnumerable<string> collection)
{
WriteLine(title);
foreach (string item in collection)
{
WriteLine($" {item}");
}
}
static void OutputPQ<TElement, TPriority>(string title,
IEnumerable<(TElement Element, TPriority Priority)> collection)
{
WriteLine(title);
foreach ((TElement, TPriority) item in collection)
{
WriteLine($" {item.Item1}: {item.Item2}");
}
}
}

View file

@ -0,0 +1,129 @@
using System.Collections.Immutable;
// Working with lists
// Simple syntax for creating a list and adding three items
List<string> cities = new();
cities.Add("London");
cities.Add("Paris");
cities.Add("Milan");
/* Alternative syntax that is converted by the compiler into
the three Add method calls above
List<string> cities = new()
{ "London", "Paris", "Milan" }; */
/* Alternative syntax that passes an
array of string values to AddRange method
List<string> cities = new();
cities.AddRange(new[] { "London", "Paris", "Milan" }); */
Output("Initial list", cities);
WriteLine($"The first city is {cities[0]}.");
WriteLine($"The last city is {cities[cities.Count - 1]}.");
cities.Insert(0, "Sydney");
Output("After inserting Sydney at index 0", cities);
cities.RemoveAt(1);
cities.Remove("Milan");
Output("After removing two cities", cities);
// Working with dictionaries
Dictionary<string, string> keywords = new();
// add using named parameters
keywords.Add(key: "int", value: "32-bit integer data type");
// add using positional parameters
keywords.Add("long", "64-bit integer data type");
keywords.Add("float", "Single precision floating point number");
/* Alternative syntax; compiler converts this to calls to Add method
Dictionary<string, string> keywords = new()
{
{ "int", "32-bit integer data type" },
{ "long", "64-bit integer data type" },
{ "float", "Single precision floating point number" },
}; */
/* Alternative syntax; compiler converts this to calls to Add method
Dictionary<string, string> keywords = new()
{
["int"] = "32-bit integer data type",
["long"] = "64-bit integer data type",
["float"] = "Single precision floating point number", // last comma is optional
}; */
Output("Dictionary keys:", keywords.Keys);
Output("Dictionary values:", keywords.Values);
WriteLine("Keywords and their definitions");
foreach (KeyValuePair<string, string> item in keywords)
{
WriteLine($" {item.Key}: {item.Value}");
}
// lookup a value using a key
string key = "long";
WriteLine($"The definition of {key} is {keywords[key]}");
// Working with queues
Queue<string> coffee = new();
coffee.Enqueue("Damir"); // front of queue
coffee.Enqueue("Andrea");
coffee.Enqueue("Ronald");
coffee.Enqueue("Amin");
coffee.Enqueue("Irina"); // back of queue
Output("Initial queue from front to back", coffee);
// server handles next person in queue
string served = coffee.Dequeue();
WriteLine($"Served: {served}.");
// server handles next person in queue
served = coffee.Dequeue();
WriteLine($"Served: {served}.");
Output("Current queue from front to back", coffee);
WriteLine($"{coffee.Peek()} is next in line.");
Output("Current queue from front to back", coffee);
// Working with priority queues
PriorityQueue<string, int> vaccine = new();
// add some people
// 1 = high priority people in their 70s or poor health
// 2 = medium priority e.g. middle aged
// 3 = low priority e.g. teens and twenties
vaccine.Enqueue("Pamela", 1); // my mum (70s)
vaccine.Enqueue("Rebecca", 3); // my niece (teens)
vaccine.Enqueue("Juliet", 2); // my sister (40s)
vaccine.Enqueue("Ian", 1); // my dad (70s)
OutputPQ("Current queue for vaccination:", vaccine.UnorderedItems);
WriteLine($"{vaccine.Dequeue()} has been vaccinated.");
WriteLine($"{vaccine.Dequeue()} has been vaccinated.");
OutputPQ("Current queue for vaccination:", vaccine.UnorderedItems);
WriteLine($"{vaccine.Dequeue()} has been vaccinated.");
WriteLine("Adding Mark to queue with priority 2");
vaccine.Enqueue("Mark", 2); // me (50s)
WriteLine($"{vaccine.Peek()} will be next to be vaccinated.");
OutputPQ("Current queue for vaccination:", vaccine.UnorderedItems);
// Working with immutable collections
ImmutableList<string> immutableCities = cities.ToImmutableList();
ImmutableList<string> newList = immutableCities.Add("Rio");
Output("Immutable list of cities:", immutableCities);
Output("New list of cities:", newList);

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,50 @@
using System.Net; // IPHostEntry, Dns, IPAddress
using System.Net.NetworkInformation; // Ping, PingReply, IPStatus
// Working with URIs, DNS, and IP addresses
Write("Enter a valid web address (or press Enter): ");
string? url = ReadLine();
if (string.IsNullOrWhiteSpace(url)) // if they enter nothing...
{
// ... set a default URL
url = "https://stackoverflow.com/search?q=securestring";
}
Uri uri = new(url);
WriteLine($"URL: {url}");
WriteLine($"Scheme: {uri.Scheme}");
WriteLine($"Port: {uri.Port}");
WriteLine($"Host: {uri.Host}");
WriteLine($"Path: {uri.AbsolutePath}");
WriteLine($"Query: {uri.Query}");
IPHostEntry entry = Dns.GetHostEntry(uri.Host);
WriteLine($"{entry.HostName} has the following IP addresses:");
foreach (IPAddress address in entry.AddressList)
{
WriteLine($" {address} ({address.AddressFamily})");
}
// Pinging a server
try
{
Ping ping = new();
WriteLine("Pinging server. Please wait...");
PingReply reply = ping.Send(uri.Host);
WriteLine($"{uri.Host} was pinged and replied: {reply.Status}.");
if (reply.Status == IPStatus.Success)
{
WriteLine("Reply from {0} took {1:N0}ms",
arg0: reply.Address,
arg1: reply.RoundtripTime);
}
}
catch (Exception ex)
{
WriteLine($"{ex.GetType().ToString()} says {ex.Message}");
}

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,27 @@
using System.Numerics;
WriteLine("Working with large integers:");
WriteLine("-----------------------------------");
ulong big = ulong.MaxValue;
WriteLine($"{big,40:N0}");
BigInteger bigger =
BigInteger.Parse("123456789012345678901234567890");
WriteLine($"{bigger,40:N0}");
WriteLine("Working with complex numbers:");
Complex c1 = new(real: 4, imaginary: 2);
Complex c2 = new(real: 3, imaginary: 7);
Complex c3 = c1 + c2;
// output using default ToString implementation
WriteLine($"{c1} added to {c2} is {c3}");
// output using custom format
WriteLine("{0} + {1}i added to {2} + {3}i is {4} + {5}i",
c1.Real, c1.Imaginary,
c2.Real, c2.Imaginary,
c3.Real, c3.Imaginary);

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,28 @@
string name = "Samantha Jones";
// getting the lengths of the first and last names
int lengthOfFirst = name.IndexOf(' ');
int lengthOfLast = name.Length - lengthOfFirst - 1;
// Using Substring
string firstName = name.Substring(
startIndex: 0,
length: lengthOfFirst);
string lastName = name.Substring(
startIndex: name.Length - lengthOfLast,
length: lengthOfLast);
WriteLine($"First name: {firstName}, Last name: {lastName}");
// Using spans
ReadOnlySpan<char> nameAsSpan = name.AsSpan();
ReadOnlySpan<char> firstNameSpan = nameAsSpan[0..lengthOfFirst];
ReadOnlySpan<char> lastNameSpan = nameAsSpan[^lengthOfLast..^0];
WriteLine("First name: {0}, Last name: {1}",
arg0: firstNameSpan.ToString(),
arg1: lastNameSpan.ToString());

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,38 @@
using System.Text.RegularExpressions; // Regex
Write("Enter your age: ");
string input = ReadLine()!; // null-forgiving
Regex ageChecker = new(@"^\d+$");
if (ageChecker.IsMatch(input))
{
WriteLine("Thank you!");
}
else
{
WriteLine($"This is not a valid age: {input}");
}
string films = "\"Monsters, Inc.\",\"I, Tonya\",\"Lock, Stock and Two Smoking Barrels\"";
WriteLine($"Films to split: {films}");
string[] filmsDumb = films.Split(',');
WriteLine("Splitting with string.Split method:");
foreach (string film in filmsDumb)
{
WriteLine(film);
}
Regex csv = new(
"(?:^|,)(?=[^\"]|(\")?)\"?((?(1)[^\"]*|[^,\"]*))\"?(?=,|$)");
MatchCollection filmsSmart = csv.Matches(films);
WriteLine("Splitting with regular expression:");
foreach (Match film in filmsSmart)
{
WriteLine(film.Groups[2].Value);
}

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,45 @@
string city = "London";
WriteLine($"{city} is {city.Length} characters long.");
WriteLine($"First char is {city[0]} and third is {city[2]}.");
string cities = "Paris,Tehran,Chennai,Sydney,New York,Medellín";
string[] citiesArray = cities.Split(',');
WriteLine($"There are {citiesArray.Length} items in the array.");
foreach (string item in citiesArray)
{
WriteLine(item);
}
string fullName = "Alan Jones";
int indexOfTheSpace = fullName.IndexOf(' ');
string firstName = fullName.Substring(
startIndex: 0, length: indexOfTheSpace);
string lastName = fullName.Substring(
startIndex: indexOfTheSpace + 1);
WriteLine($"Original: {fullName}");
WriteLine($"Swapped: {lastName}, {firstName}");
string company = "Microsoft";
bool startsWithM = company.StartsWith("M");
bool containsN = company.Contains("N");
WriteLine($"Text: {company}");
WriteLine($"Starts with M: {startsWithM}, contains an N: {containsN}");
string recombined = string.Join(" => ", citiesArray);
WriteLine(recombined);
string fruit = "Apples";
decimal price = 0.39M;
DateTime when = DateTime.Today;
WriteLine($"Interpolated: {fruit} cost {price:C} on {when:dddd}.");
WriteLine(string.Format("string.Format: {0} cost {1:C} on {2:dddd}.",
arg0: fruit, arg1: price, arg2: when));

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,24 @@
using System.Text.RegularExpressions;
WriteLine("The default regular expression checks for at least one digit.");
do
{
Write("Enter a regular expression (or press ENTER to use the default): ");
string? regexp = ReadLine();
if (string.IsNullOrWhiteSpace(regexp))
{
regexp = @"^\d+$";
}
Write("Enter some input: ");
string input = ReadLine()!; // will never be null
Regex r = new(regexp);
WriteLine($"{input} matches {regexp}: {r.IsMatch(input)}");
WriteLine("Press ESC to end or any key to try again.");
}
while (ReadKey(intercept: true).Key != ConsoleKey.Escape);

View file

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Ch08Ex03NumbersAsWordsLib\Ch08Ex03NumbersAsWordsLib.csproj" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,16 @@
using Packt.Shared; // ToWords extension method
using System.Numerics; // BigInteger
Write("Enter a number up to twenty one digits long: ");
string? input = ReadLine();
if (input is null) return;
if (input.Length > 21)
{
WriteLine("I cannot handle more than twenty one digits!");
return;
}
BigInteger number = BigInteger.Parse(input);
WriteLine($"{number:N0} in words is {number.ToWords()}.");

View file

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,220 @@
using System.Diagnostics; // Trace
using System.IO; // File
using System.Numerics; // BigInteger
namespace Packt.Shared
{
public static class NumbersToWords
{
// Single-digit and small number names
private static string[] smallNumbers = new string[]
{
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen"
};
// Tens number names from twenty upwards
private static string[] tens = new string[]
{
"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy",
"eighty", "ninety"
};
// Scale number names for use during recombination
private static string[] scaleNumbers = new string[]
{
"", "thousand", "million", "billion", "trillion",
"quadrillion", "quintillion"
};
private static int groups = 7; // i.e. up to quintillion
public static string ToWords(this int number)
{
return ToWords((BigInteger)number);
}
public static string ToWords(this long number)
{
return ToWords((BigInteger)number);
}
public static string ToWords(this BigInteger number)
{
/*
Convert A Number into Words
by Richard Carr, published at http://www.blackwasp.co.uk/numbertowords.aspx
*/
/*
Zero Rule.
If the value is 0 then the number in words is 'zero' and no other rules apply.
*/
if (number == 0)
{
return "zero";
}
/*
Three Digit Rule.
The integer value is split into groups of three digits starting from the
right-hand side. Each set of three digits is then processed individually
as a number of hundreds, tens and units. Once converted to text, the
three-digit groups are recombined with the addition of the relevant scale
number (thousand, million, billion).
*/
// Array to hold the specified number of three-digit groups
int[] digitGroups = new int[groups];
// Ensure a positive number to extract from
var positive = BigInteger.Abs(number);
// Extract the three-digit groups
for (int i = 0; i < groups; i++)
{
digitGroups[i] = (int)(positive % 1000);
positive /= 1000;
}
// write to a text file in the project folder
Trace.Listeners.Add(new TextWriterTraceListener(
File.AppendText("log.txt")));
// text writer is buffered, so this option calls
// Flush() on all listeners after writing
Trace.AutoFlush = true;
// log array of group numbers
for (int x = 0; x < digitGroups.Length; x++)
{
Trace.WriteLine(string.Format(
format: "digitGroups[{0}] = {1}",
arg0: x,
arg1: digitGroups[x]));
}
// Convert each three-digit group to words
string[] groupTexts = new string[groups];
for (int i = 0; i < groups; i++)
{
// call a local function (see below)
groupTexts[i] = ThreeDigitGroupToWords(digitGroups[i]);
}
// log array of group texts
for (int x = 0; x < groupTexts.Length; x++)
{
Trace.WriteLine(string.Format(
format: "groupTexts[{0}] = {1}",
arg0: x,
arg1: groupTexts[x]));
}
/*
Recombination Rules.
When recombining the translated three-digit groups, each group except the
last is followed by a large number name and a comma, unless the group is
blank and therefore not included at all. One exception is when the final
group does not include any hundreds and there is more than one non-blank
group. In this case, the final comma is replaced with 'and'. eg.
'one billion, one million and twelve'.
*/
// Recombine the three-digit groups
string combined = groupTexts[0];
bool appendAnd;
// Determine whether an 'and' is needed
appendAnd = (digitGroups[0] > 0) && (digitGroups[0] < 100);
// Process the remaining groups in turn, smallest to largest
for (int i = 1; i < groups; i++)
{
// Only add non-zero items
if (digitGroups[i] != 0)
{
// Build the string to add as a prefix
string prefix = groupTexts[i] + " " + scaleNumbers[i];
if (combined.Length != 0)
{
prefix += appendAnd ? " and " : ", ";
}
// Opportunity to add 'and' is ended
appendAnd = false;
// Add the three-digit group to the combined string
combined = prefix + combined;
}
}
// Converts a three-digit group into English words
string ThreeDigitGroupToWords(int threeDigits)
{
// Initialise the return text
string groupText = "";
// Determine the hundreds and the remainder
int hundreds = threeDigits / 100;
int tensUnits = threeDigits % 100;
/*
Hundreds Rules.
If the hundreds portion of a three-digit group is not zero, the number of
hundreds is added as a word. If the three-digit group is exactly divisible
by one hundred, the text 'hundred' is appended. If not, the text
"hundred and" is appended. eg. 'two hundred' or 'one hundred and twelve'
*/
if (hundreds != 0)
{
groupText += smallNumbers[hundreds] + " hundred";
if (tensUnits != 0)
{
groupText += " and ";
}
}
// Determine the tens and units
int tens = tensUnits / 10;
int units = tensUnits % 10;
/* Tens Rules.
If the tens section of a three-digit group is two or higher, the appropriate
'-ty' word (twenty, thirty, etc.) is added to the text and followed by the
name of the third digit (unless the third digit is a zero, which is ignored).
If the tens and the units are both zero, no text is added. For any other value,
the name of the one or two-digit number is added as a special case.
*/
if (tens >= 2)
{
groupText += NumbersToWords.tens[tens];
if (units != 0)
{
groupText += " " + smallNumbers[units];
}
}
else if (tensUnits != 0)
groupText += smallNumbers[tensUnits];
return groupText;
}
/* Negative Rule.
Negative numbers are always preceded by the text 'negative'.
*/
if (number < 0)
{
combined = "negative " + combined;
}
return combined;
}
}
}

View file

@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Ch08Ex03NumbersAsWordsLib\Ch08Ex03NumbersAsWordsLib.csproj" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,64 @@
using Packt.Shared; // ToWords extension method
using System.Numerics; // BigInteger
namespace Ch08Ex03NumbersAsWordsTests
{
public class NumbersToWordsUnitTests
{
[Fact]
public void Test_Int32_0()
{
// arrange
int number = 0;
string expected = "zero";
// act
string actual = number.ToWords();
// assert
Assert.Equal(expected, actual);
}
[Fact]
public void Test_Int32_1234()
{
// arrange
int number = 1234;
string expected = "one thousand, two hundred and thirty four";
// act
string actual = number.ToWords();
// assert
Assert.Equal(expected, actual);
}
[Fact]
public void Test_BigInteger_18456002032011000007()
{
// arrange
BigInteger number = BigInteger.Parse("18456002032011000007");
string expected = "eighteen quintillion, four hundred and fifty six quadrillion, two trillion, thirty two billion, eleven million and seven";
// act
string actual = number.ToWords();
// assert
Assert.Equal(expected, actual);
}
[Fact]
public void Test_Int32_minus_13()
{
// arrange
int number = -13;
string expected = "negative thirteen";
// act
string actual = number.ToWords();
// assert
Assert.Equal(expected, actual);
}
}
}

View file

@ -0,0 +1 @@
global using Xunit;

View file

@ -0,0 +1,34 @@
{
"folders": [
{
"path": "WorkingWithNumbers"
},
{
"path": "WorkingWithText"
},
{
"path": "WorkingWithRegularExpressions"
},
{
"path": "WorkingWithCollections"
},
{
"path": "WorkingWithRanges"
},
{
"path": "WorkingWithNetworkResources"
},
{
"path": "Ch08Ex02RegularExpressions"
},
{
"path": "Ch08Ex03NumbersAsWordsLib"
},
{
"path": "Ch08Ex03NumbersAsWordsApp"
},
{
"path": "Ch08Ex03NumbersAsWordsTests"
}
]
}

View file

@ -0,0 +1,21 @@
partial class Program
{
static void Output(string title, IEnumerable<string> collection)
{
WriteLine(title);
foreach (string item in collection)
{
WriteLine($" {item}");
}
}
static void OutputPQ<TElement, TPriority>(string title,
IEnumerable<(TElement Element, TPriority Priority)> collection)
{
WriteLine(title);
foreach ((TElement, TPriority) item in collection)
{
WriteLine($" {item.Item1}: {item.Item2}");
}
}
}

View file

@ -0,0 +1,129 @@
using System.Collections.Immutable;
// Working with lists
// Simple syntax for creating a list and adding three items
List<string> cities = new();
cities.Add("London");
cities.Add("Paris");
cities.Add("Milan");
/* Alternative syntax that is converted by the compiler into
the three Add method calls above
List<string> cities = new()
{ "London", "Paris", "Milan" }; */
/* Alternative syntax that passes an
array of string values to AddRange method
List<string> cities = new();
cities.AddRange(new[] { "London", "Paris", "Milan" }); */
Output("Initial list", cities);
WriteLine($"The first city is {cities[0]}.");
WriteLine($"The last city is {cities[cities.Count - 1]}.");
cities.Insert(0, "Sydney");
Output("After inserting Sydney at index 0", cities);
cities.RemoveAt(1);
cities.Remove("Milan");
Output("After removing two cities", cities);
// Working with dictionaries
Dictionary<string, string> keywords = new();
// add using named parameters
keywords.Add(key: "int", value: "32-bit integer data type");
// add using positional parameters
keywords.Add("long", "64-bit integer data type");
keywords.Add("float", "Single precision floating point number");
/* Alternative syntax; compiler converts this to calls to Add method
Dictionary<string, string> keywords = new()
{
{ "int", "32-bit integer data type" },
{ "long", "64-bit integer data type" },
{ "float", "Single precision floating point number" },
}; */
/* Alternative syntax; compiler converts this to calls to Add method
Dictionary<string, string> keywords = new()
{
["int"] = "32-bit integer data type",
["long"] = "64-bit integer data type",
["float"] = "Single precision floating point number", // last comma is optional
}; */
Output("Dictionary keys:", keywords.Keys);
Output("Dictionary values:", keywords.Values);
WriteLine("Keywords and their definitions");
foreach (KeyValuePair<string, string> item in keywords)
{
WriteLine($" {item.Key}: {item.Value}");
}
// lookup a value using a key
string key = "long";
WriteLine($"The definition of {key} is {keywords[key]}");
// Working with queues
Queue<string> coffee = new();
coffee.Enqueue("Damir"); // front of queue
coffee.Enqueue("Andrea");
coffee.Enqueue("Ronald");
coffee.Enqueue("Amin");
coffee.Enqueue("Irina"); // back of queue
Output("Initial queue from front to back", coffee);
// server handles next person in queue
string served = coffee.Dequeue();
WriteLine($"Served: {served}.");
// server handles next person in queue
served = coffee.Dequeue();
WriteLine($"Served: {served}.");
Output("Current queue from front to back", coffee);
WriteLine($"{coffee.Peek()} is next in line.");
Output("Current queue from front to back", coffee);
// Working with priority queues
PriorityQueue<string, int> vaccine = new();
// add some people
// 1 = high priority people in their 70s or poor health
// 2 = medium priority e.g. middle aged
// 3 = low priority e.g. teens and twenties
vaccine.Enqueue("Pamela", 1); // my mum (70s)
vaccine.Enqueue("Rebecca", 3); // my niece (teens)
vaccine.Enqueue("Juliet", 2); // my sister (40s)
vaccine.Enqueue("Ian", 1); // my dad (70s)
OutputPQ("Current queue for vaccination:", vaccine.UnorderedItems);
WriteLine($"{vaccine.Dequeue()} has been vaccinated.");
WriteLine($"{vaccine.Dequeue()} has been vaccinated.");
OutputPQ("Current queue for vaccination:", vaccine.UnorderedItems);
WriteLine($"{vaccine.Dequeue()} has been vaccinated.");
WriteLine("Adding Mark to queue with priority 2");
vaccine.Enqueue("Mark", 2); // me (50s)
WriteLine($"{vaccine.Peek()} will be next to be vaccinated.");
OutputPQ("Current queue for vaccination:", vaccine.UnorderedItems);
// Working with immutable collections
ImmutableList<string> immutableCities = cities.ToImmutableList();
ImmutableList<string> newList = immutableCities.Add("Rio");
Output("Immutable list of cities:", immutableCities);
Output("New list of cities:", newList);

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,50 @@
using System.Net; // IPHostEntry, Dns, IPAddress
using System.Net.NetworkInformation; // Ping, PingReply, IPStatus
// Working with URIs, DNS, and IP addresses
Write("Enter a valid web address (or press Enter): ");
string? url = ReadLine();
if (string.IsNullOrWhiteSpace(url)) // if they enter nothing...
{
// ... set a default URL
url = "https://stackoverflow.com/search?q=securestring";
}
Uri uri = new(url);
WriteLine($"URL: {url}");
WriteLine($"Scheme: {uri.Scheme}");
WriteLine($"Port: {uri.Port}");
WriteLine($"Host: {uri.Host}");
WriteLine($"Path: {uri.AbsolutePath}");
WriteLine($"Query: {uri.Query}");
IPHostEntry entry = Dns.GetHostEntry(uri.Host);
WriteLine($"{entry.HostName} has the following IP addresses:");
foreach (IPAddress address in entry.AddressList)
{
WriteLine($" {address} ({address.AddressFamily})");
}
// Pinging a server
try
{
Ping ping = new();
WriteLine("Pinging server. Please wait...");
PingReply reply = ping.Send(uri.Host);
WriteLine($"{uri.Host} was pinged and replied: {reply.Status}.");
if (reply.Status == IPStatus.Success)
{
WriteLine("Reply from {0} took {1:N0}ms",
arg0: reply.Address,
arg1: reply.RoundtripTime);
}
}
catch (Exception ex)
{
WriteLine($"{ex.GetType().ToString()} says {ex.Message}");
}

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,27 @@
using System.Numerics;
WriteLine("Working with large integers:");
WriteLine("-----------------------------------");
ulong big = ulong.MaxValue;
WriteLine($"{big,40:N0}");
BigInteger bigger =
BigInteger.Parse("123456789012345678901234567890");
WriteLine($"{bigger,40:N0}");
WriteLine("Working with complex numbers:");
Complex c1 = new(real: 4, imaginary: 2);
Complex c2 = new(real: 3, imaginary: 7);
Complex c3 = c1 + c2;
// output using default ToString implementation
WriteLine($"{c1} added to {c2} is {c3}");
// output using custom format
WriteLine("{0} + {1}i added to {2} + {3}i is {4} + {5}i",
c1.Real, c1.Imaginary,
c2.Real, c2.Imaginary,
c3.Real, c3.Imaginary);

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,28 @@
string name = "Samantha Jones";
// getting the lengths of the first and last names
int lengthOfFirst = name.IndexOf(' ');
int lengthOfLast = name.Length - lengthOfFirst - 1;
// Using Substring
string firstName = name.Substring(
startIndex: 0,
length: lengthOfFirst);
string lastName = name.Substring(
startIndex: name.Length - lengthOfLast,
length: lengthOfLast);
WriteLine($"First name: {firstName}, Last name: {lastName}");
// Using spans
ReadOnlySpan<char> nameAsSpan = name.AsSpan();
ReadOnlySpan<char> firstNameSpan = nameAsSpan[0..lengthOfFirst];
ReadOnlySpan<char> lastNameSpan = nameAsSpan[^lengthOfLast..^0];
WriteLine("First name: {0}, Last name: {1}",
arg0: firstNameSpan.ToString(),
arg1: lastNameSpan.ToString());

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,38 @@
using System.Text.RegularExpressions; // Regex
Write("Enter your age: ");
string input = ReadLine()!; // null-forgiving
Regex ageChecker = new(@"^\d+$");
if (ageChecker.IsMatch(input))
{
WriteLine("Thank you!");
}
else
{
WriteLine($"This is not a valid age: {input}");
}
string films = "\"Monsters, Inc.\",\"I, Tonya\",\"Lock, Stock and Two Smoking Barrels\"";
WriteLine($"Films to split: {films}");
string[] filmsDumb = films.Split(',');
WriteLine("Splitting with string.Split method:");
foreach (string film in filmsDumb)
{
WriteLine(film);
}
Regex csv = new(
"(?:^|,)(?=[^\"]|(\")?)\"?((?(1)[^\"]*|[^,\"]*))\"?(?=,|$)");
MatchCollection filmsSmart = csv.Matches(films);
WriteLine("Splitting with regular expression:");
foreach (Match film in filmsSmart)
{
WriteLine(film.Groups[2].Value);
}

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,45 @@
string city = "London";
WriteLine($"{city} is {city.Length} characters long.");
WriteLine($"First char is {city[0]} and third is {city[2]}.");
string cities = "Paris,Tehran,Chennai,Sydney,New York,Medellín";
string[] citiesArray = cities.Split(',');
WriteLine($"There are {citiesArray.Length} items in the array.");
foreach (string item in citiesArray)
{
WriteLine(item);
}
string fullName = "Alan Jones";
int indexOfTheSpace = fullName.IndexOf(' ');
string firstName = fullName.Substring(
startIndex: 0, length: indexOfTheSpace);
string lastName = fullName.Substring(
startIndex: indexOfTheSpace + 1);
WriteLine($"Original: {fullName}");
WriteLine($"Swapped: {lastName}, {firstName}");
string company = "Microsoft";
bool startsWithM = company.StartsWith("M");
bool containsN = company.Contains("N");
WriteLine($"Text: {company}");
WriteLine($"Starts with M: {startsWithM}, contains an N: {containsN}");
string recombined = string.Join(" => ", citiesArray);
WriteLine(recombined);
string fruit = "Apples";
decimal price = 0.39M;
DateTime when = DateTime.Today;
WriteLine($"Interpolated: {fruit} cost {price:C} on {when:dddd}.");
WriteLine(string.Format("string.Format: {0} cost {1:C} on {2:dddd}.",
arg0: fruit, arg1: price, arg2: when));

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Using Include="System.Console" Static="true" />
</ItemGroup>
</Project>