|
2 | 2 | * COPYRIGHT: See COPYING in the top level directory |
3 | 3 | * PROJECT: FileHandler |
4 | 4 | * FILE: FileHandler/FileHandleRenameExtension.cs |
5 | | - * PURPOSE: Extension for FileHandleRename |
6 | | - * PROGRAMER: Peter Geinitz (Wayfarer) |
| 5 | + * PURPOSE: Unified safe rename helpers (append/remove/replace/reorder) |
| 6 | + * PROGRAMER: Peter Geinitz (Wayfarer) – Refactor by ChatGPT |
7 | 7 | */ |
8 | 8 |
|
9 | | -// ReSharper disable MemberCanBeInternal |
10 | | - |
11 | 9 | using System; |
12 | 10 | using System.Linq; |
13 | | -using System.Text.RegularExpressions; |
14 | 11 |
|
15 | 12 | namespace FileHandler; |
16 | 13 |
|
17 | 14 | /// <summary> |
18 | | -/// Some string Extensions |
| 15 | +/// String helpers for renaming files. |
| 16 | +/// All operations share a unified input normalization pipeline, |
| 17 | +/// but preserve the outward behavior of the original implementation. |
19 | 18 | /// </summary> |
20 | 19 | public static class FileHandleRenameExtension |
21 | 20 | { |
22 | 21 | /// <summary> |
23 | | - /// The regex Instance |
24 | | - /// </summary> |
25 | | - private static readonly Regex Regex = new(@"\D+"); |
26 | | - |
27 | | - /// <summary> |
28 | | - /// Removes the appendage. |
| 22 | + /// Removes an appendage if present. |
29 | 23 | /// </summary> |
30 | 24 | /// <param name="str">The string.</param> |
31 | 25 | /// <param name="appendage">The appendage.</param> |
32 | | - /// <param name="comparison">The string comparison option.</param> |
33 | | - /// <returns> |
34 | | - /// string with the removed appendage |
35 | | - /// </returns> |
36 | | - /// <exception cref="ArgumentNullException"> |
37 | | - /// str or appendage was empty |
38 | | - /// </exception> |
| 26 | + /// <param name="comparison">The comparison.</param> |
| 27 | + /// <returns>New File name.</returns> |
39 | 28 | public static string RemoveAppendage(this string str, string appendage, |
40 | 29 | StringComparison comparison = StringComparison.OrdinalIgnoreCase) |
41 | 30 | { |
42 | | - ArgumentNullException.ThrowIfNull(str); |
43 | | - |
44 | | - ArgumentNullException.ThrowIfNull(appendage); |
| 31 | + str = NormalizeInput(str); |
| 32 | + appendage = NormalizeSubInput(appendage); |
45 | 33 |
|
46 | 34 | return !str.StartsWith(appendage, comparison) |
47 | 35 | ? str |
48 | | - : str.Remove(0, appendage.Length); |
| 36 | + : str.Substring(appendage.Length); |
49 | 37 | } |
50 | 38 |
|
51 | 39 | /// <summary> |
52 | | - /// Adds the appendage. |
| 40 | + /// Adds an appendage if missing. |
53 | 41 | /// </summary> |
54 | 42 | /// <param name="str">The string.</param> |
55 | 43 | /// <param name="appendage">The appendage.</param> |
56 | | - /// <param name="comparison">The string comparison option.</param> |
57 | | - /// <returns> |
58 | | - /// string with added appendage |
59 | | - /// </returns> |
60 | | - /// <exception cref="ArgumentNullException"> |
61 | | - /// str or appendage was empty |
62 | | - /// </exception> |
| 44 | + /// <param name="comparison">The comparison.</param> |
| 45 | + /// <returns>New File name.</returns> |
63 | 46 | public static string AddAppendage(this string str, string appendage, |
64 | 47 | StringComparison comparison = StringComparison.OrdinalIgnoreCase) |
65 | 48 | { |
66 | | - ArgumentNullException.ThrowIfNull(str); |
| 49 | + str = NormalizeInput(str); |
| 50 | + appendage = NormalizeSubInput(appendage); |
67 | 51 |
|
68 | | - ArgumentNullException.ThrowIfNull(appendage); |
69 | | - |
70 | | - return str.StartsWith(appendage, comparison) ? str : string.Concat(appendage, str); |
| 52 | + return str.StartsWith(appendage, comparison) |
| 53 | + ? str |
| 54 | + : appendage + str; |
71 | 55 | } |
72 | 56 |
|
73 | 57 | /// <summary> |
74 | | - /// Replaces the part. |
| 58 | + /// Replaces a substring only if it exists. |
75 | 59 | /// </summary> |
76 | 60 | /// <param name="str">The string.</param> |
77 | 61 | /// <param name="targetStr">The target string.</param> |
78 | | - /// <param name="update">The update string.</param> |
79 | | - /// <param name="comparison">The string comparison option.</param> |
80 | | - /// <returns> |
81 | | - /// string with replaced substring |
82 | | - /// </returns> |
83 | | - /// <exception cref="ArgumentNullException">str was empty</exception> |
| 62 | + /// <param name="update">The update.</param> |
| 63 | + /// <param name="comparison">The comparison.</param> |
| 64 | + /// <returns>New File name.</returns> |
84 | 65 | public static string ReplacePart(this string str, string targetStr, string update, |
85 | 66 | StringComparison comparison = StringComparison.Ordinal) |
86 | 67 | { |
87 | | - ArgumentNullException.ThrowIfNull(str); |
| 68 | + str = NormalizeInput(str); |
88 | 69 |
|
89 | 70 | if (string.IsNullOrEmpty(targetStr)) |
90 | | - { |
91 | 71 | return str; |
92 | | - } |
93 | 72 |
|
94 | | - return !str.Contains(targetStr, comparison) ? str : str.Replace(targetStr, update); |
| 73 | + return str.Contains(targetStr, comparison) |
| 74 | + ? str.Replace(targetStr, update) |
| 75 | + : str; |
95 | 76 | } |
96 | 77 |
|
97 | 78 | /// <summary> |
98 | | - /// Reorders Numbers in a string and appends them. |
| 79 | + /// Reorders all digits to the end and appends them with a separator. |
| 80 | + /// Preserves original non-digit order and old behavior. |
99 | 81 | /// </summary> |
100 | 82 | /// <param name="str">The string.</param> |
101 | | - /// <returns>New string</returns> |
| 83 | + /// <returns>New File name.</returns> |
102 | 84 | public static string ReOrderNumbers(this string str) |
103 | 85 | { |
| 86 | + str = NormalizeInput(str); |
| 87 | + |
104 | 88 | if (string.IsNullOrEmpty(str)) |
105 | | - { |
106 | 89 | return str; |
107 | | - } |
108 | 90 |
|
109 | | - var charsToRemove = Regex.Split(str); |
110 | | - var numbers = string.Concat(charsToRemove); |
| 91 | + // Extract numeric parts |
| 92 | + var digits = string.Concat(str.Where(char.IsDigit)); |
| 93 | + |
| 94 | + // Remove digits from the original string |
| 95 | + var nonDigits = string.Concat(str.Where(c => !char.IsDigit(c))); |
| 96 | + |
| 97 | + // Append separator + digits only if digits exist |
| 98 | + if (string.IsNullOrEmpty(digits)) |
| 99 | + return str; |
| 100 | + |
| 101 | + return nonDigits + FileHandlerResources.Append + digits; |
| 102 | + } |
| 103 | + |
| 104 | + /// <summary> |
| 105 | + /// Ensures safe null handling and returns the normalized input. |
| 106 | + /// Does NOT modify casing, punctuation, ordering, etc. |
| 107 | + /// </summary> |
| 108 | + /// <param name="str">The string.</param> |
| 109 | + /// <returns>Normalized File name.</returns> |
| 110 | + /// <exception cref="System.ArgumentNullException"></exception> |
| 111 | + private static string NormalizeInput(string str) |
| 112 | + { |
| 113 | + // preserve original NullException behavior for compatibility |
| 114 | + ArgumentNullException.ThrowIfNull(str); |
| 115 | + return str; |
| 116 | + } |
111 | 117 |
|
112 | | - return string.Concat( |
113 | | - charsToRemove.Where(c => !string.IsNullOrEmpty(c)) |
114 | | - .Aggregate(str, (current, c) => current.Replace(c, string.Empty)), FileHandlerResources.Append, |
115 | | - numbers); |
| 118 | + /// <summary> |
| 119 | + /// Normalizes append/remove/replace inputs. |
| 120 | + /// </summary> |
| 121 | + /// <param name="str">The string.</param> |
| 122 | + /// <returns>Normalized File name.</returns> |
| 123 | + /// <exception cref="System.ArgumentNullException"></exception> |
| 124 | + private static string NormalizeSubInput(string str) |
| 125 | + { |
| 126 | + ArgumentNullException.ThrowIfNull(str); |
| 127 | + return str; |
116 | 128 | } |
117 | 129 | } |
0 commit comments