@@ -47,6 +47,7 @@ public RuntimeScalar transliterate(RuntimeScalar originalString, int ctx) {
4747 StringBuilder result = new StringBuilder ();
4848 int count = 0 ;
4949 Integer lastChar = null ;
50+ boolean lastCharWasTransliterated = false ; // Track if last char came from transliteration
5051
5152 // For complement mode, we need to track replacement index
5253 Map <Integer , Integer > complementMap = new HashMap <>();
@@ -78,10 +79,12 @@ public RuntimeScalar transliterate(RuntimeScalar originalString, int ctx) {
7879 if (deleteUnmatched && replacementChars .isEmpty ()) {
7980 // Delete mode with empty replacement
8081 lastChar = null ;
82+ lastCharWasTransliterated = false ;
8183 } else if (replacementChars .isEmpty ()) {
8284 // Empty replacement, non-delete mode - keep character as is
83- if (!squashDuplicates || lastChar == null || lastChar != codePoint ) {
85+ if (!squashDuplicates || lastChar == null || ! lastCharWasTransliterated || lastChar != codePoint ) {
8486 appendCodePoint (result , codePoint );
87+ lastCharWasTransliterated = true ;
8588 }
8689 lastChar = codePoint ;
8790 } else {
@@ -112,6 +115,7 @@ public RuntimeScalar transliterate(RuntimeScalar originalString, int ctx) {
112115 } else if (deleteUnmatched ) {
113116 // With /d modifier, delete characters that have no replacement
114117 lastChar = null ;
118+ lastCharWasTransliterated = false ;
115119 continue ; // Skip this character (delete it)
116120 } else {
117121 // Use last replacement character
@@ -121,9 +125,10 @@ public RuntimeScalar transliterate(RuntimeScalar originalString, int ctx) {
121125 }
122126 }
123127
124- if (!squashDuplicates || lastChar == null || !lastChar .equals (mappedChar )) {
128+ if (!squashDuplicates || lastChar == null || !lastCharWasTransliterated || ! lastChar .equals (mappedChar )) {
125129 appendCodePoint (result , mappedChar );
126130 lastChar = mappedChar ;
131+ lastCharWasTransliterated = true ;
127132 }
128133 }
129134 } else {
@@ -133,22 +138,24 @@ public RuntimeScalar transliterate(RuntimeScalar originalString, int ctx) {
133138 // We need to preserve it for squashing logic
134139 } else if (translationMap .containsKey (codePoint )) {
135140 int mappedChar = translationMap .get (codePoint );
136- // Handle squash duplicates
137- if (!squashDuplicates || lastChar == null || !lastChar .equals (mappedChar )) {
141+ // Handle squash duplicates - only squash if the last char was also transliterated
142+ if (!squashDuplicates || lastChar == null || !lastCharWasTransliterated || ! lastChar .equals (mappedChar )) {
138143 appendCodePoint (result , mappedChar );
139144 lastChar = mappedChar ;
140- } else {
145+ lastCharWasTransliterated = true ;
141146 }
142147 } else {
143148 // No mapping found (shouldn't happen if compilation is correct)
144149 appendCodePoint (result , codePoint );
145150 lastChar = codePoint ;
151+ lastCharWasTransliterated = false ;
146152 }
147153 }
148154 } else {
149155 // Character not matched - keep as is
150156 appendCodePoint (result , codePoint );
151157 lastChar = codePoint ;
158+ lastCharWasTransliterated = false ;
152159 }
153160 }
154161
0 commit comments