Reduce string allocations by regex

pull/9337/head
Bond_009 1 year ago
parent df8346cd63
commit 48263078b4

@ -40,7 +40,7 @@ namespace Emby.Naming.AudioBook
var value = match.Groups["chapter"]; var value = match.Groups["chapter"];
if (value.Success) 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; result.ChapterNumber = intValue;
} }
@ -52,7 +52,7 @@ namespace Emby.Naming.AudioBook
var value = match.Groups["part"]; var value = match.Groups["part"];
if (value.Success) 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; result.PartNumber = intValue;
} }

@ -47,7 +47,7 @@ namespace Emby.Naming.AudioBook
var value = match.Groups["year"]; var value = match.Groups["year"];
if (value.Success) 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; result.Year = intValue;
} }

@ -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[] VideoExtraRules = new[]
{ {
new ExtraRule( new ExtraRule(
@ -797,16 +787,6 @@ namespace Emby.Naming.Common
/// </summary> /// </summary>
public EpisodeExpression[] EpisodeExpressions { get; set; } 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> /// <summary>
/// Gets or sets list of video file extensions. /// Gets or sets list of video file extensions.
/// </summary> /// </summary>
@ -877,16 +857,6 @@ namespace Emby.Naming.Common
/// </summary> /// </summary>
public Regex[] CleanStringRegexes { get; private set; } = Array.Empty<Regex>(); 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> /// <summary>
/// Compiles raw regex strings into regexes. /// Compiles raw regex strings into regexes.
/// </summary> /// </summary>
@ -894,8 +864,6 @@ namespace Emby.Naming.Common
{ {
CleanDateTimeRegexes = CleanDateTimes.Select(Compile).ToArray(); CleanDateTimeRegexes = CleanDateTimes.Select(Compile).ToArray();
CleanStringRegexes = CleanStrings.Select(Compile).ToArray(); CleanStringRegexes = CleanStrings.Select(Compile).ToArray();
EpisodeWithoutSeasonRegexes = EpisodeWithoutSeasonExpressions.Select(Compile).ToArray();
EpisodeMultiPartRegexes = EpisodeMultiPartExpressions.Select(Compile).ToArray();
} }
private Regex Compile(string exp) private Regex Compile(string exp)

@ -113,7 +113,7 @@ namespace Emby.Naming.TV
if (expression.DateTimeFormats.Length > 0) if (expression.DateTimeFormats.Length > 0)
{ {
if (DateTime.TryParseExact( if (DateTime.TryParseExact(
match.Groups[0].Value, match.Groups[0].ValueSpan,
expression.DateTimeFormats, expression.DateTimeFormats,
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
DateTimeStyles.None, DateTimeStyles.None,
@ -125,7 +125,7 @@ namespace Emby.Naming.TV
result.Success = true; 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.Year = date.Year;
result.Month = date.Month; result.Month = date.Month;
@ -138,12 +138,12 @@ namespace Emby.Naming.TV
} }
else if (expression.IsNamed) 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; 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; result.EpisodeNumber = num;
} }
@ -158,7 +158,7 @@ namespace Emby.Naming.TV
if (nextIndex >= name.Length if (nextIndex >= name.Length
|| !"0123456789iIpP".Contains(name[nextIndex], StringComparison.Ordinal)) || !"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; result.EndingEpisodeNumber = num;
} }
@ -170,12 +170,12 @@ namespace Emby.Naming.TV
} }
else 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; 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; result.EpisodeNumber = num;
} }

@ -43,7 +43,7 @@ namespace Emby.Naming.Video
&& match.Groups.Count == 5 && match.Groups.Count == 5
&& match.Groups[1].Success && match.Groups[1].Success
&& match.Groups[2].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); result = new CleanDateTimeResult(match.Groups[1].Value.TrimEnd(), year);
return true; return true;

@ -56,7 +56,7 @@ namespace Emby.Naming.Video
} }
else if (rule.RuleType == ExtraRuleType.Regex) 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); var isMatch = Regex.IsMatch(filename, rule.Token, RegexOptions.IgnoreCase | RegexOptions.Compiled);

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

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

@ -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)); 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 @ // 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 // In theory this will cut out most if not all 'control' characters which should help minimize any weirdness

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

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

Loading…
Cancel
Save