Repository: SubtitleEdit/subtitleedit (2026-06-25T17:04:47Z)

Issue:
Bug "Remove text for hearing impaired"
In previous releases the "Remove text between" portion of the box had an option to put in your own custom characters.  The beginning and ending characters were limited to one character.

Now the box has been changed to allow you to type multiple characters.  However only the first character is actually used in processing.  This happens without any error message.


Discussion:

Patch:
diff --git a/src/libse/Forms/RemoveTextForHI.cs b/src/libse/Forms/RemoveTextForHI.cs
index 8b21b27dfc..dbb61d7ef9 100644
--- a/src/libse/Forms/RemoveTextForHI.cs
+++ b/src/libse/Forms/RemoveTextForHI.cs
@@ -1517,7 +1517,10 @@ private static string RemoveTextBetweenTags(string startTag, string endTag, stri
                     break;
                 }
 
-                text = text.Remove(start, end - start + 1);
+                // 'end' is the start index of endTag; remove through the whole end tag, not
+                // just its first character, so multi-character custom tags (e.g. "<<"/">>",
+                // "<i>"/"</i>") are fully stripped instead of leaving the trailing characters.
+                text = text.Remove(start, end - start + endTag.Length);
                 if (start > 3 && text.Length - start > 1 &&
                     text[start] == ':' && text[start - 1] == ' ' && ".?!".Contains(text[start - 2]))
                 {


Test patch:
diff --git a/tests/libse/Forms/RemoveTextForHITest.cs b/tests/libse/Forms/RemoveTextForHITest.cs
new file mode 100644
index 0000000000..88a2fb1f85
--- /dev/null
+++ b/tests/libse/Forms/RemoveTextForHITest.cs
@@ -0,0 +1,116 @@
+using Nikse.SubtitleEdit.Core.Common;
+using Nikse.SubtitleEdit.Core.Forms;
+
+namespace LibSETests.Forms;
+
+public class RemoveTextForHITest
+{
+    private static RemoveTextForHI MakeRemover(string customStart = "", string customEnd = "")
+    {
+        var settings = new RemoveTextForHISettings(new Subtitle())
+        {
+            OnlyIfInSeparateLine = false,
+            RemoveTextBetweenSquares = false,
+            RemoveTextBetweenBrackets = false,
+            RemoveTextBetweenParentheses = false,
+            RemoveTextBetweenQuestionMarks = false,
+            RemoveTextBetweenCustomTags = false,
+            RemoveInterjections = false,
+            RemoveIfAllUppercase = false,
+            RemoveTextBeforeColon = false,
+            RemoveWhereContains = false,
+            RemoveIfOnlyMusicSymbols = false,
+            CustomStart = customStart,
+            CustomEnd = customEnd,
+        };
+
+        return new RemoveTextForHI(settings);
+    }
+
+    // --- Custom tags: the bug from issue #11850 ---
+
+    [Fact]
+    public void Custom_SingleChar_RemovesBetween()
+    {
+        var remover = MakeRemover("(", ")");
+        remover.Settings.RemoveTextBetweenCustomTags = true;
+
+        Assert.Equal("Hello", remover.RemoveHearImpairedTags("(noise) Hello"));
+    }
+
+    [Fact]
+    public void Custom_MultiChar_RemovesWholeEndTag()
+    {
+        // Before the fix only the first char of the end tag (">") was removed,
+        // leaving "> Hello".
+        var remover = MakeRemover("<<", ">>");
+        remover.Settings.RemoveTextBetweenCustomTags = true;
+
+        Assert.Equal("Hello", remover.RemoveHearImpairedTags("<<noise>> Hello"));
+    }
+
+    [Fact]
+    public void Custom_MultiChar_HtmlLikeTags()
+    {
+        var remover = MakeRemover("<i>", "</i>");
+        remover.Settings.RemoveTextBetweenCustomTags = true;
+
+        Assert.Equal("Hello", remover.RemoveHearImpairedTags("<i>noise</i> Hello"));
+    }
+
+    [Fact]
+    public void Custom_MultiChar_InMiddle()
+    {
+        var remover = MakeRemover("[[", "]]");
+        remover.Settings.RemoveTextBetweenCustomTags = true;
+
+        Assert.Equal("Hello there", remover.RemoveHearImpairedTags("Hello [[noise]] there"));
+    }
+
+    // --- Predefined tags: regression guards (must keep working after the fix) ---
+
+    [Fact]
+    public void Squares_RemovesBetween()
+    {
+        var remover = MakeRemover();
+        remover.Settings.RemoveTextBetweenSquares = true;
+
+        Assert.Equal("Hello", remover.RemoveHearImpairedTags("[noise] Hello"));
+    }
+
+    [Fact]
+    public void Squares_WithColon_RemovesNameAndColon()
+    {
+        var remover = MakeRemover();
+        remover.Settings.RemoveTextBetweenSquares = true;
+
+        Assert.Equal("Hello", remover.RemoveHearImpairedTags("[MAN]: Hello"));
+    }
+
+    [Fact]
+    public void Parentheses_RemovesBetween()
+    {
+        var remover = MakeRemover();
+        remover.Settings.RemoveTextBetweenParentheses = true;
+
+        Assert.Equal("Bye", remover.RemoveHearImpairedTags("(SIGH) Bye"));
+    }
+
+    [Fact]
+    public void Parentheses_WithColon_RemovesNameAndColon()
+    {
+        var remover = MakeRemover();
+        remover.Settings.RemoveTextBetweenParentheses = true;
+
+        Assert.Equal("Hello", remover.RemoveHearImpairedTags("(MAN): Hello"));
+    }
+
+    [Fact]
+    public void CurlyBrackets_RemovesBetween()
+    {
+        var remover = MakeRemover();
+        remover.Settings.RemoveTextBetweenBrackets = true;
+
+        Assert.Equal("Hello", remover.RemoveHearImpairedTags("{noise} Hello"));
+    }
+}