Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
####################################################################
# Editor Configuration (Updated 2023-07-26)
# Editor Configuration (Updated 2025-12-05)
#
# (c)2023 superdev GmbH
# (c)2025 superdev GmbH
####################################################################

root = true
Expand All @@ -15,7 +15,7 @@ tab_width = 2
indent_style = space
indent_size = 4
tab_width = 4
end_of_line = crlf
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = false
max_line_length = 200
Expand Down Expand Up @@ -112,6 +112,7 @@ dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_compound_assignment = true:suggestion
dotnet_style_prefer_simplified_interpolation = true:suggestion
dotnet_style_prefer_collection_expression = false:silent
dotnet_style_namespace_match_folder = true:suggestion
dotnet_style_operator_placement_when_wrapping = beginning_of_line
csharp_style_unused_value_expression_statement_preference = discard_variable:none
Expand Down Expand Up @@ -175,4 +176,7 @@ dotnet_diagnostic.IDE0051.severity = warning
dotnet_diagnostic.CS1591.severity = none

# CA1416: Validate platform compatibility
dotnet_diagnostic.CA1416.severity = suggestion
dotnet_diagnostic.CA1416.severity = suggestion

# LocalVariableHidesMember: Local variable hides member
resharper_local_variable_hides_member_highlighting = none
7 changes: 7 additions & 0 deletions Diacritics.sln.DotSettings
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=Aerzte/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Delemont/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Del_00E9mont/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Gefaess/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Gef_00E4_00DF/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=_00C4rzte/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
6 changes: 3 additions & 3 deletions Diacritics/Diacritics.csproj
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net462;netstandard1.2;netstandard2.0;netstandard2.1;net7.0;net8.0;net9.0</TargetFrameworks>
<TargetFrameworks>net48;netstandard1.2;netstandard2.0;netstandard2.1;net7.0;net8.0;net9.0</TargetFrameworks>
<OutputType>Library</OutputType>
<SignAssembly>True</SignAssembly>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
</PropertyGroup>

<!--NuGet package-->
Expand All @@ -28,7 +30,6 @@
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<EmbedAllSources>true</EmbedAllSources>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<SignAssembly>True</SignAssembly>
</PropertyGroup>

<ItemGroup>
Expand All @@ -40,7 +41,6 @@
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>


<ItemGroup Condition=" '$(TargetFramework)' == 'net462' ">
<Reference Include="System" />
Expand Down
77 changes: 42 additions & 35 deletions Diacritics/DiacriticsMapper.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using Diacritics.AccentMappings;
using Diacritics.Internals;

// ReSharper disable ConvertIfStatementToNullCoalescingAssignment

namespace Diacritics
{
public class DiacriticsMapper : IDiacriticsMapper
{
#region DiacriticsMapper.Current

private static Lazy<IDiacriticsMapper> Implementation;
private static Lazy<IDiacriticsMapper> Implementation = null!;

static DiacriticsMapper()
{
Expand Down Expand Up @@ -43,35 +44,37 @@ public DiacriticsMapper(params IAccentMapping[] mappings)

private static IDictionary<char, MappingReplacement> ConvertMappings(IAccentMapping[] accentMappings)
{
if (accentMappings == null)
{
throw new ArgumentNullException(nameof(accentMappings));
}

var all = new Dictionary<char, MappingReplacement>();

if (accentMappings != null)
foreach (var accentMapping in accentMappings)
{
foreach (var accentMapping in accentMappings)
var mappings = accentMapping.Mapping;
foreach (var mapping in mappings)
{
var mappings = accentMapping.Mapping;
foreach (var mapping in mappings)
if (!all.TryGetValue(mapping.Key, out var mappingReplacement))
{
if (!all.TryGetValue(mapping.Key, out var mappingReplacement))
all[mapping.Key] = mapping.Value;
}
else
{
// Merge existing DecomposeTitle and Decompose properties,
// unless the current mapping replacement defines them.
if (mappingReplacement.DecomposeTitle == null)
{
all[mapping.Key] = mapping.Value;
mappingReplacement.DecomposeTitle = mapping.Value.DecomposeTitle;
}
else

if (mappingReplacement.Decompose == null)
{
// Merge existing DecomposeTitle and Decompose properties,
// unless the current mapping replacement defines them.
if (mappingReplacement.DecomposeTitle == null)
{
mappingReplacement.DecomposeTitle = mapping.Value.DecomposeTitle;
}

if (mappingReplacement.Decompose == null)
{
mappingReplacement.Decompose = mapping.Value.Decompose;
}

all[mapping.Key] = mappingReplacement;
mappingReplacement.Decompose = mapping.Value.Decompose;
}

all[mapping.Key] = mappingReplacement;
}
}
}
Expand All @@ -90,28 +93,33 @@ IEnumerator IEnumerable.GetEnumerator()
return this.GetEnumerator();
}

public string RemoveDiacritics(string source)
[return: NotNullIfNotNull(nameof(source))]
public string? RemoveDiacritics(string? source)
{
return this.RemoveDiacritics(source, options: null);
}

public string RemoveDiacritics(string source, DiacriticsOptions options)
[return: NotNullIfNotNull(nameof(source))]
public string? RemoveDiacritics(string? source, DiacriticsOptions? options)
{
return RemoveDiacritics(source, this.diacriticsMappings, options);
}

public string RemoveDiacritics(string source, IAccentMapping[] mappings)
[return: NotNullIfNotNull(nameof(source))]
public string? RemoveDiacritics(string? source, IAccentMapping[] mappings)
{
return this.RemoveDiacritics(source, mappings, options: null);
}

public string RemoveDiacritics(string source, IAccentMapping[] mappings, DiacriticsOptions options)
[return: NotNullIfNotNull(nameof(source))]
public string? RemoveDiacritics(string? source, IAccentMapping[] mappings, DiacriticsOptions? options)
{
var diacriticsMappings = ConvertMappings(mappings);
return RemoveDiacritics(source, diacriticsMappings, options);
}

private static string RemoveDiacritics(string source, IDictionary<char, MappingReplacement> diacriticsMappings, DiacriticsOptions options)
[return: NotNullIfNotNull(nameof(source))]
private static string? RemoveDiacritics(string? source, IDictionary<char, MappingReplacement> diacriticsMappings, DiacriticsOptions? options)
{
if (string.IsNullOrWhiteSpace(source))
{
Expand All @@ -120,18 +128,17 @@ private static string RemoveDiacritics(string source, IDictionary<char, MappingR

var decompose = options?.Decompose ?? false;

var result = StringBuilderCache.Acquire(source.Length);
// ReSharper disable once RedundantSuppressNullableWarningExpression
var result = StringBuilderCache.Acquire(source!.Length);

for (var currentIndex = 0; currentIndex < source.Length; currentIndex++)
{
var currentChar = source[currentIndex];

if (diacriticsMappings.TryGetValue(currentChar, out var mappingReplacement))
{
var replacement = (decompose ? currentIndex == 0 ?
mappingReplacement.DecomposeTitle ?? mappingReplacement.Decompose :
mappingReplacement.Decompose :
mappingReplacement.Base) ?? mappingReplacement.Base;
var replacement = (decompose ? currentIndex == 0 ? mappingReplacement.DecomposeTitle ?? mappingReplacement.Decompose : mappingReplacement.Decompose : mappingReplacement.Base) ??
mappingReplacement.Base;

result.Append(replacement);
}
Expand All @@ -144,12 +151,12 @@ private static string RemoveDiacritics(string source, IDictionary<char, MappingR
return StringBuilderCache.GetStringAndRelease(result);
}

public bool HasDiacritics(string source)
public bool HasDiacritics(string? source)
{
return this.HasDiacritics(source, options: null);
}

public bool HasDiacritics(string source, DiacriticsOptions options)
public bool HasDiacritics(string? source, DiacriticsOptions? options)
{
return source != this.RemoveDiacritics(source, options);
}
Expand Down
17 changes: 11 additions & 6 deletions Diacritics/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,42 +1,47 @@

using System.Diagnostics.CodeAnalysis;
using Diacritics.AccentMappings;

namespace Diacritics.Extensions
{
public static class StringExtensions
{
/// <inheritdoc cref="IDiacriticsMapper.RemoveDiacritics(string)"/>
public static string RemoveDiacritics(this string source)
[return: NotNullIfNotNull(nameof(source))]
public static string? RemoveDiacritics(this string? source)
{
return DiacriticsMapper.Current.RemoveDiacritics(source);
}

/// <inheritdoc cref="IDiacriticsMapper.RemoveDiacritics(string, DiacriticsOptions)"/>
public static string RemoveDiacritics(this string source, DiacriticsOptions options)
[return: NotNullIfNotNull(nameof(source))]
public static string? RemoveDiacritics(this string? source, DiacriticsOptions options)
{
return DiacriticsMapper.Current.RemoveDiacritics(source, options);
}

/// <inheritdoc cref="IDiacriticsMapper.RemoveDiacritics(string, IAccentMapping[])"/>
public static string RemoveDiacritics(this string source, params IAccentMapping[] mappings)
[return: NotNullIfNotNull(nameof(source))]
public static string? RemoveDiacritics(this string? source, params IAccentMapping[] mappings)
{
return DiacriticsMapper.Current.RemoveDiacritics(source, mappings);
}

/// <inheritdoc cref="IDiacriticsMapper.RemoveDiacritics(string, IAccentMapping[], DiacriticsOptions)"/>
public static string RemoveDiacritics(this string source, IAccentMapping[] mappings, DiacriticsOptions options)
[return: NotNullIfNotNull(nameof(source))]
public static string? RemoveDiacritics(this string? source, IAccentMapping[] mappings, DiacriticsOptions options)
{
return DiacriticsMapper.Current.RemoveDiacritics(source, mappings, options);
}

/// <inheritdoc cref="IDiacriticsMapper.HasDiacritics(string)"/>
public static bool HasDiacritics(this string source)
public static bool HasDiacritics(this string? source)
{
return DiacriticsMapper.Current.HasDiacritics(source);
}

/// <inheritdoc cref="IDiacriticsMapper.HasDiacritics(string, DiacriticsOptions)"/>
public static bool HasDiacritics(this string source, DiacriticsOptions options)
public static bool HasDiacritics(this string? source, DiacriticsOptions options)
{
return DiacriticsMapper.Current.HasDiacritics(source, options);
}
Expand Down
12 changes: 6 additions & 6 deletions Diacritics/IDiacriticsMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,43 +16,43 @@ public interface IDiacriticsMapper : IEnumerable<KeyValuePair<char, MappingRepla
/// Removes any diacritical characters from <paramref name="source"/>.
/// </summary>
/// <param name="source">The source string.</param>
string RemoveDiacritics(string source);
string? RemoveDiacritics(string? source);

/// <summary>
/// Removes any diacritical characters from <paramref name="source"/>.
/// </summary>
/// <param name="source">The source string.</param>
/// <param name="options">The options.</param>
string RemoveDiacritics(string source, DiacriticsOptions options);
string? RemoveDiacritics(string? source, DiacriticsOptions? options);

/// <summary>
/// Removes any diacritical characters from <paramref name="source"/> using custom accent mappings.
/// </summary>
/// <param name="source">The source string.</param>
/// <param name="mappings">The accent mapping to be used to replace diacritical characters.</param>
string RemoveDiacritics(string source, IAccentMapping[] mappings);
string? RemoveDiacritics(string? source, IAccentMapping[] mappings);

/// <summary>
/// Removes any diacritical characters from <paramref name="source"/> using custom accent mappings.
/// </summary>
/// <param name="source">The source string.</param>
/// <param name="mappings">The accent mapping to be used to replace diacritical characters.</param>
/// <param name="options">The options.</param>
string RemoveDiacritics(string source, IAccentMapping[] mappings, DiacriticsOptions options);
string? RemoveDiacritics(string? source, IAccentMapping[] mappings, DiacriticsOptions? options);

/// <summary>
/// Checks if the given <paramref name="source"/> string contains any diacritical characters.
/// </summary>
/// <param name="source">The source string.</param>
/// <returns><c>true</c> if the source string contains any diacritical characters; otherwise, <c>false</c>.</returns>
bool HasDiacritics(string source);
bool HasDiacritics(string? source);

/// <summary>
/// Checks if the given <paramref name="source"/> string contains any diacritical characters.
/// </summary>
/// <param name="source">The source string.</param>
/// <param name="options">The options.</param>
/// <returns><c>true</c> if the source string contains any diacritical characters; otherwise, <c>false</c>.</returns>
bool HasDiacritics(string source, DiacriticsOptions options);
bool HasDiacritics(string? source, DiacriticsOptions? options);
}
}
Loading