]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Cache regex instances in most cases (#27699)
authorPieter-Jan Briers <pieterjan.briers+git@gmail.com>
Sun, 5 May 2024 22:57:32 +0000 (00:57 +0200)
committerGitHub <noreply@github.com>
Sun, 5 May 2024 22:57:32 +0000 (08:57 +1000)
Using static Regex functions that take in a pattern is bad because the pattern constantly needs to be re-parsed. With https://github.com/space-wizards/RobustToolbox/pull/5107, the engine has an analyzer to warn for this practice now.

This commit brings most of content up to snuff already, though some of the tricker code I left for somebody else.

Content.Server/Speech/EntitySystems/FrenchAccentSystem.cs
Content.Server/Speech/EntitySystems/FrontalLispSystem.cs
Content.Server/Speech/EntitySystems/LizardAccentSystem.cs
Content.Server/Speech/EntitySystems/MobsterAccentSystem.cs
Content.Server/Speech/EntitySystems/MothAccentSystem.cs
Content.Server/Speech/EntitySystems/ParrotAccentSystem.cs
Content.Server/Speech/EntitySystems/PirateAccentSystem.cs
Content.Server/Speech/EntitySystems/ScrambledAccentSystem.cs
Content.Server/Speech/EntitySystems/SouthernAccentSystem.cs
Content.Shared/Preferences/HumanoidCharacterProfile.cs

index 563728873252f9350e08699afaf2024037ac2671..f6d259c11532052ba2e187d9edeae63154faf6f4 100644 (file)
@@ -10,6 +10,10 @@ public sealed class FrenchAccentSystem : EntitySystem
 {
     [Dependency] private readonly ReplacementAccentSystem _replacement = default!;
 
+    private static readonly Regex RegexTh = new(@"th", RegexOptions.IgnoreCase);
+    private static readonly Regex RegexStartH = new(@"(?<!\w)h", RegexOptions.IgnoreCase);
+    private static readonly Regex RegexSpacePunctuation = new(@"(?<=\w\w)[!?;:](?!\w)", RegexOptions.IgnoreCase);
+
     public override void Initialize()
     {
         base.Initialize();
@@ -23,17 +27,14 @@ public sealed class FrenchAccentSystem : EntitySystem
 
         msg = _replacement.ApplyReplacements(msg, "french");
 
-        // replaces th with dz 
-        msg = Regex.Replace(msg, @"th", "'z", RegexOptions.IgnoreCase);
+        // replaces th with dz
+        msg = RegexTh.Replace(msg, "'z");
 
         // removes the letter h from the start of words.
-        msg = Regex.Replace(msg, @"(?<!\w)[h]", "'", RegexOptions.IgnoreCase);
+        msg = RegexStartH.Replace(msg, "'");
 
         // spaces out ! ? : and ;.
-        msg = Regex.Replace(msg, @"(?<=\w\w)!(?!\w)", " !", RegexOptions.IgnoreCase);
-        msg = Regex.Replace(msg, @"(?<=\w\w)[?](?!\w)", " ?", RegexOptions.IgnoreCase);
-        msg = Regex.Replace(msg, @"(?<=\w\w)[;](?!\w)", " ;", RegexOptions.IgnoreCase);
-        msg = Regex.Replace(msg, @"(?<=\w\w)[:](?!\w)", " :", RegexOptions.IgnoreCase);
+        msg = RegexSpacePunctuation.Replace(msg, " $&");
 
         return msg;
     }
index 96e3620ecf0e83bb60a50d43dbbe4cb4dcc256bf..1508a8b2d4342b7886a1f5e68dce4da29cb2a9e8 100644 (file)
@@ -5,6 +5,13 @@ namespace Content.Server.Speech.EntitySystems;
 
 public sealed class FrontalLispSystem : EntitySystem
 {
+    // @formatter:off
+    private static readonly Regex RegexUpperTh = new(@"[T]+[Ss]+|[S]+[Cc]+(?=[IiEeYy]+)|[C]+(?=[IiEeYy]+)|[P][Ss]+|([S]+[Tt]+|[T]+)(?=[Ii]+[Oo]+[Uu]*[Nn]*)|[C]+[Hh]+(?=[Ii]*[Ee]*)|[Z]+|[S]+|[X]+(?=[Ee]+)");
+    private static readonly Regex RegexLowerTh = new(@"[t]+[s]+|[s]+[c]+(?=[iey]+)|[c]+(?=[iey]+)|[p][s]+|([s]+[t]+|[t]+)(?=[i]+[o]+[u]*[n]*)|[c]+[h]+(?=[i]*[e]*)|[z]+|[s]+|[x]+(?=[e]+)");
+    private static readonly Regex RegexUpperEcks = new(@"[E]+[Xx]+[Cc]*|[X]+");
+    private static readonly Regex RegexLowerEcks = new(@"[e]+[x]+[c]*|[x]+");
+    // @formatter:on
+
     public override void Initialize()
     {
         base.Initialize();
@@ -16,11 +23,11 @@ public sealed class FrontalLispSystem : EntitySystem
         var message = args.Message;
 
         // handles ts, sc(i|e|y), c(i|e|y), ps, st(io(u|n)), ch(i|e), z, s
-        message = Regex.Replace(message, @"[T]+[Ss]+|[S]+[Cc]+(?=[IiEeYy]+)|[C]+(?=[IiEeYy]+)|[P][Ss]+|([S]+[Tt]+|[T]+)(?=[Ii]+[Oo]+[Uu]*[Nn]*)|[C]+[Hh]+(?=[Ii]*[Ee]*)|[Z]+|[S]+|[X]+(?=[Ee]+)", "TH");
-        message = Regex.Replace(message, @"[t]+[s]+|[s]+[c]+(?=[iey]+)|[c]+(?=[iey]+)|[p][s]+|([s]+[t]+|[t]+)(?=[i]+[o]+[u]*[n]*)|[c]+[h]+(?=[i]*[e]*)|[z]+|[s]+|[x]+(?=[e]+)", "th");
+        message = RegexUpperTh.Replace(message, "TH");
+        message = RegexLowerTh.Replace(message, "th");
         // handles ex(c), x
-        message = Regex.Replace(message, @"[E]+[Xx]+[Cc]*|[X]+", "EKTH");
-        message = Regex.Replace(message, @"[e]+[x]+[c]*|[x]+", "ekth");
+        message = RegexUpperEcks.Replace(message, "EKTH");
+        message = RegexLowerEcks.Replace(message, "ekth");
 
         args.Message = message;
     }
index a7e21016a2d5816055de74ee6a0f1009ed84a376..81a57cb848cddfd97538e31ae238a953f3a47c65 100644 (file)
@@ -5,6 +5,12 @@ namespace Content.Server.Speech.EntitySystems;
 
 public sealed class LizardAccentSystem : EntitySystem
 {
+    private static readonly Regex RegexLowerS = new("s+");
+    private static readonly Regex RegexUpperS = new("S+");
+    private static readonly Regex RegexInternalX = new(@"(\w)x");
+    private static readonly Regex RegexLowerEndX = new(@"\bx([\-|r|R]|\b)");
+    private static readonly Regex RegexUpperEndX = new(@"\bX([\-|r|R]|\b)");
+
     public override void Initialize()
     {
         base.Initialize();
@@ -16,15 +22,15 @@ public sealed class LizardAccentSystem : EntitySystem
         var message = args.Message;
 
         // hissss
-        message = Regex.Replace(message, "s+", "sss");
+        message = RegexLowerS.Replace(message, "sss");
         // hiSSS
-        message = Regex.Replace(message, "S+", "SSS");
+        message = RegexUpperS.Replace(message, "SSS");
         // ekssit
-        message = Regex.Replace(message, @"(\w)x", "$1kss");
+        message = RegexInternalX.Replace(message, "$1kss");
         // ecks
-        message = Regex.Replace(message, @"\bx([\-|r|R]|\b)", "ecks$1");
+        message = RegexLowerEndX.Replace(message, "ecks$1");
         // eckS
-        message = Regex.Replace(message, @"\bX([\-|r|R]|\b)", "ECKS$1");
+        message = RegexUpperEndX.Replace(message, "ECKS$1");
 
         args.Message = message;
     }
index d1a6a049d5e0262a3ea35de3f1c684ca44ef85d6..0e9b0a34ef2797567f784d9143c58db16d66d5fa 100644 (file)
@@ -1,4 +1,3 @@
-using System.Globalization;
 using System.Linq;
 using System.Text.RegularExpressions;
 using Content.Server.Speech.Components;
@@ -8,30 +7,17 @@ namespace Content.Server.Speech.EntitySystems;
 
 public sealed class MobsterAccentSystem : EntitySystem
 {
+    private static readonly Regex RegexIng = new(@"(?<=\w\w)(in)g(?!\w)", RegexOptions.IgnoreCase);
+    private static readonly Regex RegexLowerOr = new(@"(?<=\w)o[Rr](?=\w)");
+    private static readonly Regex RegexUpperOr = new(@"(?<=\w)O[Rr](?=\w)");
+    private static readonly Regex RegexLowerAr = new(@"(?<=\w)a[Rr](?=\w)");
+    private static readonly Regex RegexUpperAr = new(@"(?<=\w)A[Rr](?=\w)");
+    private static readonly Regex RegexFirstWord = new(@"^(\S+)");
+    private static readonly Regex RegexLastWord = new(@"(\S+)$");
+
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly ReplacementAccentSystem _replacement = default!;
 
-    private static readonly Dictionary<string, string> DirectReplacements = new()
-    {
-        { "let me", "lemme" },
-        { "should", "oughta" },
-        { "the", "da" },
-        { "them", "dem" },
-        { "attack", "whack" },
-        { "kill", "whack" },
-        { "murder", "whack" },
-        { "dead", "sleepin' with da fishies"},
-        { "hey", "ey'o" },
-        { "hi", "ey'o"},
-        { "hello", "ey'o"},
-        { "rules", "roolz" },
-        { "you", "yous" },
-        { "have to", "gotta" },
-        { "going to", "boutta" },
-        { "about to", "boutta" },
-        { "here", "'ere" }
-    };
-
     public override void Initialize()
     {
         base.Initialize();
@@ -51,20 +37,20 @@ public sealed class MobsterAccentSystem : EntitySystem
         // thinking -> thinkin'
         // king -> king
         //Uses captures groups to make sure the captialization of IN is kept
-        msg = Regex.Replace(msg, @"(?<=\w\w)(in)g(?!\w)", "$1'", RegexOptions.IgnoreCase);
+        msg = RegexIng.Replace(msg, "$1'");
 
         // or -> uh and ar -> ah in the middle of words (fuhget, tahget)
-        msg = Regex.Replace(msg, @"(?<=\w)o[Rr](?=\w)", "uh");
-        msg = Regex.Replace(msg, @"(?<=\w)O[Rr](?=\w)", "UH");
-        msg = Regex.Replace(msg, @"(?<=\w)a[Rr](?=\w)", "ah");
-        msg = Regex.Replace(msg, @"(?<=\w)A[Rr](?=\w)", "AH");
+        msg = RegexLowerOr.Replace(msg, "uh");
+        msg = RegexUpperOr.Replace(msg, "UH");
+        msg = RegexLowerAr.Replace(msg, "ah");
+        msg = RegexUpperAr.Replace(msg, "AH");
 
         // Prefix
         if (_random.Prob(0.15f))
         {
             //Checks if the first word of the sentence is all caps
             //So the prefix can be allcapped and to not resanitize the captial
-            var firstWordAllCaps = !Regex.Match(msg, @"^(\S+)").Value.Any(char.IsLower);
+            var firstWordAllCaps = !RegexFirstWord.Match(msg).Value.Any(char.IsLower);
             var pick = _random.Next(1, 2);
 
             // Reverse sanitize capital
@@ -84,7 +70,7 @@ public sealed class MobsterAccentSystem : EntitySystem
         {
             //Checks if the last word of the sentence is all caps
             //So the suffix can be allcapped
-            var lastWordAllCaps = !Regex.Match(msg, @"(\S+)$").Value.Any(char.IsLower);
+            var lastWordAllCaps = !RegexLastWord.Match(msg).Value.Any(char.IsLower);
             var suffix = "";
             if (component.IsBoss)
             {
@@ -94,7 +80,7 @@ public sealed class MobsterAccentSystem : EntitySystem
             else
             {
                 var pick = _random.Next(1, 3);
-                suffix = Loc.GetString($"accent-mobster-suffix-minion-{pick}");                
+                suffix = Loc.GetString($"accent-mobster-suffix-minion-{pick}");
             }
             if (lastWordAllCaps)
                 suffix = suffix.ToUpper();
index 3de4651b4af2cb45045934de0290a87910952ba4..84b79d4ce98b6576762bee939747a88960a82f2b 100644 (file)
@@ -5,6 +5,9 @@ namespace Content.Server.Speech.EntitySystems;
 
 public sealed class MothAccentSystem : EntitySystem
 {
+    private static readonly Regex RegexLowerBuzz = new Regex("z{1,3}");
+    private static readonly Regex RegexUpperBuzz = new Regex("Z{1,3}");
+
     public override void Initialize()
     {
         base.Initialize();
@@ -16,10 +19,10 @@ public sealed class MothAccentSystem : EntitySystem
         var message = args.Message;
 
         // buzzz
-        message = Regex.Replace(message, "z{1,3}", "zzz");
+        message = RegexLowerBuzz.Replace(message, "zzz");
         // buZZZ
-        message = Regex.Replace(message, "Z{1,3}", "ZZZ");
-        
+        message = RegexUpperBuzz.Replace(message, "ZZZ");
+
         args.Message = message;
     }
 }
index 10437c235d68a75a221281917ae0597a94e3d9b1..ae8fe522b9b41a4dd21ae50671d98f6ff374fef4 100644 (file)
@@ -7,6 +7,8 @@ namespace Content.Server.Speech.EntitySystems;
 
 public sealed partial class ParrotAccentSystem : EntitySystem
 {
+    private static readonly Regex WordCleanupRegex = new Regex("[^A-Za-z0-9 -]");
+
     [Dependency] private readonly IRobustRandom _random = default!;
 
     public override void Initialize()
@@ -27,7 +29,7 @@ public sealed partial class ParrotAccentSystem : EntitySystem
         if (_random.Prob(entity.Comp.LongestWordRepeatChance))
         {
             // Don't count non-alphanumeric characters as parts of words
-            var cleaned = Regex.Replace(message, "[^A-Za-z0-9 -]", string.Empty);
+            var cleaned = WordCleanupRegex.Replace(message, string.Empty);
             // Split on whitespace and favor words towards the end of the message
             var words = cleaned.Split(null).Reverse();
             // Find longest word
index 9f5f8080b9b1e2f263df229daf9abdf4ffd002b2..84298cbf01a668f8149e8bf7b4cf045639404d7e 100644 (file)
@@ -7,6 +7,8 @@ namespace Content.Server.Speech.EntitySystems;
 
 public sealed class PirateAccentSystem : EntitySystem
 {
+    private static readonly Regex FirstWordAllCapsRegex = new(@"^(\S+)");
+
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly ReplacementAccentSystem _replacement = default!;
 
@@ -26,7 +28,7 @@ public sealed class PirateAccentSystem : EntitySystem
             return msg;
         //Checks if the first word of the sentence is all caps
         //So the prefix can be allcapped and to not resanitize the captial
-        var firstWordAllCaps = !Regex.Match(msg, @"^(\S+)").Value.Any(char.IsLower);
+        var firstWordAllCaps = !FirstWordAllCapsRegex.Match(msg).Value.Any(char.IsLower);
 
         var pick = _random.Pick(component.PirateWords);
         var pirateWord = Loc.GetString(pick);
index 37b267bec2b618f730fc72e5da75d9d7040f2e8c..8a61c0ea500fb0f6b241d45fe6c4ff6b1ab0ae81 100644 (file)
@@ -7,6 +7,8 @@ namespace Content.Server.Speech.EntitySystems
 {
     public sealed class ScrambledAccentSystem : EntitySystem
     {
+        private static readonly Regex RegexLoneI = new(@"(?<=\ )i(?=[\ \.\?]|$)");
+
         [Dependency] private readonly IRobustRandom _random = default!;
 
         public override void Initialize()
@@ -34,7 +36,7 @@ namespace Content.Server.Speech.EntitySystems
             msg = msg[0].ToString().ToUpper() + msg.Remove(0, 1);
 
             // Capitalize lone i's
-            msg = Regex.Replace(msg, @"(?<=\ )i(?=[\ \.\?]|$)", "I");
+            msg = RegexLoneI.Replace(msg, "I");
             return msg;
         }
 
index 4d401367cca1672f9a98ac3adc60fed687f8fb8e..b9260eb84415c030616a130e18639ec86049a70e 100644 (file)
@@ -5,8 +5,12 @@ namespace Content.Server.Speech.EntitySystems;
 
 public sealed class SouthernAccentSystem : EntitySystem
 {
+    private static readonly Regex RegexIng = new(@"ing\b");
+    private static readonly Regex RegexAnd = new(@"\band\b");
+    private static readonly Regex RegexDve = new("d've");
+
     [Dependency] private readonly ReplacementAccentSystem _replacement = default!;
-    
+
     public override void Initialize()
     {
         base.Initialize();
@@ -20,9 +24,9 @@ public sealed class SouthernAccentSystem : EntitySystem
         message = _replacement.ApplyReplacements(message, "southern");
 
         //They shoulda started runnin' an' hidin' from me!
-        message = Regex.Replace(message, @"ing\b", "in'");
-        message = Regex.Replace(message, @"\band\b", "an'");
-        message = Regex.Replace(message, "d've", "da");
+        message = RegexIng.Replace(message, "in'");
+        message = RegexAnd.Replace(message, "an'");
+        message = RegexDve.Replace(message, "da");
         args.Message = message;
     }
 };
index 3f3444195ca7695903c228042be30879196e2dac..f9b037c8ab5cc5cea54b9751716206bf903a9b1b 100644 (file)
@@ -26,6 +26,9 @@ namespace Content.Shared.Preferences
     [Serializable, NetSerializable]
     public sealed partial class HumanoidCharacterProfile : ICharacterProfile
     {
+        private static readonly Regex RestrictedNameRegex = new("[^A-Z,a-z,0-9, -]");
+        private static readonly Regex ICNameCaseRegex = new(@"^(?<word>\w)|\b(?<word>\w)(?=\w*$)");
+
         public const int MaxNameLength = 32;
         public const int MaxDescLength = 512;
 
@@ -418,15 +421,13 @@ namespace Content.Shared.Preferences
 
             if (configManager.GetCVar(CCVars.RestrictedNames))
             {
-                name = Regex.Replace(name, @"[^A-Z,a-z,0-9, -]", string.Empty);
+                name = RestrictedNameRegex.Replace(name, string.Empty);
             }
 
             if (configManager.GetCVar(CCVars.ICNameCase))
             {
                 // This regex replaces the first character of the first and last words of the name with their uppercase version
-                name = Regex.Replace(name,
-                @"^(?<word>\w)|\b(?<word>\w)(?=\w*$)",
-                m => m.Groups["word"].Value.ToUpper());
+                name = ICNameCaseRegex.Replace(name, m => m.Groups["word"].Value.ToUpper());
             }
 
             if (string.IsNullOrEmpty(name))