Browse Source

Reduce string allocations by regex

Bond_009 2 years ago
parent
commit
48263078b4

+ 2 - 2
Emby.Naming/AudioBook/AudioBookFilePathParser.cs

@@ -40,7 +40,7 @@ namespace Emby.Naming.AudioBook
                         var value = match.Groups["chapter"];
                         if (value.Success)
                         {
-                            if (int.TryParse(value.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
+                            if (int.TryParse(value.ValueSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
                             {
                                 result.ChapterNumber = intValue;
                             }
@@ -52,7 +52,7 @@ namespace Emby.Naming.AudioBook
                         var value = match.Groups["part"];
                         if (value.Success)
                         {
-                            if (int.TryParse(value.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
+                            if (int.TryParse(value.ValueSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
                             {
                                 result.PartNumber = intValue;
                             }

+ 1 - 1
Emby.Naming/AudioBook/AudioBookNameParser.cs

@@ -47,7 +47,7 @@ namespace Emby.Naming.AudioBook
                         var value = match.Groups["year"];
                         if (value.Success)
                         {
-                            if (int.TryParse(value.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
+                            if (int.TryParse(value.ValueSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
                             {
                                 result.Year = intValue;
                             }

+ 0 - 32
Emby.Naming/Common/NamingOptions.cs

@@ -453,16 +453,6 @@ namespace Emby.Naming.Common
                 },
             };
 
-            EpisodeWithoutSeasonExpressions = new[]
-            {
-                @"[/\._ \-]()([0-9]+)(-[0-9]+)?"
-            };
-
-            EpisodeMultiPartExpressions = new[]
-            {
-                @"^[-_ex]+([0-9]+(?:(?:[a-i]|\\.[1-9])(?![0-9]))?)"
-            };
-
             VideoExtraRules = new[]
             {
                 new ExtraRule(
@@ -797,16 +787,6 @@ namespace Emby.Naming.Common
         /// </summary>
         public EpisodeExpression[] EpisodeExpressions { get; set; }
 
-        /// <summary>
-        /// Gets or sets list of raw episode without season regular expressions strings.
-        /// </summary>
-        public string[] EpisodeWithoutSeasonExpressions { get; set; }
-
-        /// <summary>
-        /// Gets or sets list of raw multi-part episodes regular expressions strings.
-        /// </summary>
-        public string[] EpisodeMultiPartExpressions { get; set; }
-
         /// <summary>
         /// Gets or sets list of video file extensions.
         /// </summary>
@@ -877,16 +857,6 @@ namespace Emby.Naming.Common
         /// </summary>
         public Regex[] CleanStringRegexes { get; private set; } = Array.Empty<Regex>();
 
-        /// <summary>
-        /// Gets list of episode without season regular expressions.
-        /// </summary>
-        public Regex[] EpisodeWithoutSeasonRegexes { get; private set; } = Array.Empty<Regex>();
-
-        /// <summary>
-        /// Gets list of multi-part episode regular expressions.
-        /// </summary>
-        public Regex[] EpisodeMultiPartRegexes { get; private set; } = Array.Empty<Regex>();
-
         /// <summary>
         /// Compiles raw regex strings into regexes.
         /// </summary>
@@ -894,8 +864,6 @@ namespace Emby.Naming.Common
         {
             CleanDateTimeRegexes = CleanDateTimes.Select(Compile).ToArray();
             CleanStringRegexes = CleanStrings.Select(Compile).ToArray();
-            EpisodeWithoutSeasonRegexes = EpisodeWithoutSeasonExpressions.Select(Compile).ToArray();
-            EpisodeMultiPartRegexes = EpisodeMultiPartExpressions.Select(Compile).ToArray();
         }
 
         private Regex Compile(string exp)

+ 7 - 7
Emby.Naming/TV/EpisodePathParser.cs

@@ -113,7 +113,7 @@ namespace Emby.Naming.TV
                     if (expression.DateTimeFormats.Length > 0)
                     {
                         if (DateTime.TryParseExact(
-                            match.Groups[0].Value,
+                            match.Groups[0].ValueSpan,
                             expression.DateTimeFormats,
                             CultureInfo.InvariantCulture,
                             DateTimeStyles.None,
@@ -125,7 +125,7 @@ namespace Emby.Naming.TV
                             result.Success = true;
                         }
                     }
-                    else if (DateTime.TryParse(match.Groups[0].Value, out date))
+                    else if (DateTime.TryParse(match.Groups[0].ValueSpan, out date))
                     {
                         result.Year = date.Year;
                         result.Month = date.Month;
@@ -138,12 +138,12 @@ namespace Emby.Naming.TV
                 }
                 else if (expression.IsNamed)
                 {
-                    if (int.TryParse(match.Groups["seasonnumber"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var num))
+                    if (int.TryParse(match.Groups["seasonnumber"].ValueSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out var num))
                     {
                         result.SeasonNumber = num;
                     }
 
-                    if (int.TryParse(match.Groups["epnumber"].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
+                    if (int.TryParse(match.Groups["epnumber"].ValueSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
                     {
                         result.EpisodeNumber = num;
                     }
@@ -158,7 +158,7 @@ namespace Emby.Naming.TV
                         if (nextIndex >= name.Length
                             || !"0123456789iIpP".Contains(name[nextIndex], StringComparison.Ordinal))
                         {
-                            if (int.TryParse(endingNumberGroup.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
+                            if (int.TryParse(endingNumberGroup.ValueSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
                             {
                                 result.EndingEpisodeNumber = num;
                             }
@@ -170,12 +170,12 @@ namespace Emby.Naming.TV
                 }
                 else
                 {
-                    if (int.TryParse(match.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var num))
+                    if (int.TryParse(match.Groups[1].ValueSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out var num))
                     {
                         result.SeasonNumber = num;
                     }
 
-                    if (int.TryParse(match.Groups[2].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
+                    if (int.TryParse(match.Groups[2].ValueSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
                     {
                         result.EpisodeNumber = num;
                     }

+ 1 - 1
Emby.Naming/Video/CleanDateTimeParser.cs

@@ -43,7 +43,7 @@ namespace Emby.Naming.Video
                 && match.Groups.Count == 5
                 && match.Groups[1].Success
                 && match.Groups[2].Success
-                && int.TryParse(match.Groups[2].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
+                && int.TryParse(match.Groups[2].ValueSpan, NumberStyles.Integer, CultureInfo.InvariantCulture, out var year))
             {
                 result = new CleanDateTimeResult(match.Groups[1].Value.TrimEnd(), year);
                 return true;

+ 1 - 1
Emby.Naming/Video/ExtraRuleResolver.cs

@@ -56,7 +56,7 @@ namespace Emby.Naming.Video
                 }
                 else if (rule.RuleType == ExtraRuleType.Regex)
                 {
-                    var filename = Path.GetFileName(path);
+                    var filename = Path.GetFileName(path.AsSpan());
 
                     var isMatch = Regex.IsMatch(filename, rule.Token, RegexOptions.IgnoreCase | RegexOptions.Compiled);
 

+ 4 - 5
Emby.Naming/Video/VideoListResolver.cs

@@ -176,16 +176,15 @@ namespace Emby.Naming.Video
             }
 
             // There are no span overloads for regex unfortunately
-            var tmpTestFilename = testFilename.ToString();
-            if (CleanStringParser.TryClean(tmpTestFilename, namingOptions.CleanStringRegexes, out var cleanName))
+            if (CleanStringParser.TryClean(testFilename.ToString(), namingOptions.CleanStringRegexes, out var cleanName))
             {
-                tmpTestFilename = cleanName.Trim();
+                testFilename = cleanName.AsSpan().Trim();
             }
 
             // The CleanStringParser should have removed common keywords etc.
-            return string.IsNullOrEmpty(tmpTestFilename)
+            return testFilename.IsEmpty
                    || testFilename[0] == '-'
-                   || Regex.IsMatch(tmpTestFilename, @"^\[([^]]*)\]", RegexOptions.Compiled);
+                   || Regex.IsMatch(testFilename, @"^\[([^]]*)\]", RegexOptions.Compiled);
         }
     }
 }

+ 2 - 7
Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs

@@ -313,13 +313,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
             return result;
         }
 
-        private static bool IsIgnored(string filename)
-        {
-            // Ignore samples
-            Match m = Regex.Match(filename, @"\bsample\b", RegexOptions.IgnoreCase | RegexOptions.Compiled);
-
-            return m.Success;
-        }
+        private static bool IsIgnored(ReadOnlySpan<char> filename)
+            => Regex.IsMatch(filename, @"\bsample\b", RegexOptions.IgnoreCase | RegexOptions.Compiled);
 
         private static bool ContainsFile(IReadOnlyList<VideoInfo> result, FileSystemMetadata file)
         {

+ 1 - 1
Jellyfin.Server.Implementations/Users/UserManager.cs

@@ -740,7 +740,7 @@ namespace Jellyfin.Server.Implementations.Users
             throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)", nameof(name));
         }
 
-        private static bool IsValidUsername(string name)
+        private static bool IsValidUsername(ReadOnlySpan<char> name)
         {
             // This is some regex that matches only on unicode "word" characters, as well as -, _ and @
             // In theory this will cut out most if not all 'control' characters which should help minimize any weirdness

+ 3 - 3
MediaBrowser.MediaEncoding/Encoder/EncoderValidator.cs

@@ -277,7 +277,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
 
             if (match.Success)
             {
-                if (Version.TryParse(match.Groups[1].Value, out var result))
+                if (Version.TryParse(match.Groups[1].ValueSpan, out var result))
                 {
                     return result;
                 }
@@ -327,8 +327,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
                 RegexOptions.Multiline))
             {
                 var version = new Version(
-                    int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture),
-                    int.Parse(match.Groups["minor"].Value, CultureInfo.InvariantCulture));
+                    int.Parse(match.Groups["major"].ValueSpan, CultureInfo.InvariantCulture),
+                    int.Parse(match.Groups["minor"].ValueSpan, CultureInfo.InvariantCulture));
 
                 map.Add(match.Groups["name"].Value, version);
             }

+ 0 - 2
tests/Jellyfin.Naming.Tests/Common/NamingOptionsTest.cs

@@ -12,8 +12,6 @@ namespace Jellyfin.Naming.Tests.Common
 
             Assert.NotEmpty(options.CleanDateTimeRegexes);
             Assert.NotEmpty(options.CleanStringRegexes);
-            Assert.NotEmpty(options.EpisodeWithoutSeasonRegexes);
-            Assert.NotEmpty(options.EpisodeMultiPartRegexes);
         }
 
         [Fact]