| Bytes | Lang | Time | Link |
|---|---|---|---|
| 087 | AWK | 241205T211205Z | xrs |
| 422 | Scala 3 | 240507T134331Z | 138 Aspe |
| 052 | Perl 5 pl | 240506T142742Z | Xcali |
| 108 | R | 240504T170911Z | int 21h |
| 078 | Python 3 | 221219T125207Z | U13-Forw |
| 046 | K ngn/k | 221212T105027Z | doug |
| 064 | Ruby | 221212T010254Z | Jeremy |
| 100 | C clang | 221025T154740Z | jdt |
| 042 | Raku | 221101T194313Z | andm |
| 074 | Perl 5 | 221031T220948Z | Kjetil S |
| nan | Shell | 221027T190452Z | Olivier |
| 021 | Japt v2.0a0 | 221025T162225Z | Kamil Dr |
| 111 | PHP | 221025T135424Z | Ratchet2 |
| 075 | Ruby | 221025T132704Z | Jordan |
| 051 | Python | 221026T135821Z | Teck-fre |
| 065 | PHP 8.x | 221026T111337Z | Ismael M |
| 083 | Excel ms365 | 221025T141005Z | JvdV |
| 089 | Red | 221026T064407Z | Galen Iv |
| 169 | Desmos | 221026T061329Z | Aiden Ch |
| 011 | Vyxal s | 221026T005446Z | lyxal |
| 025 | Charcoal | 221026T001434Z | Neil |
| 087 | Retina 0.8.2 | 221025T235809Z | Neil |
| 062 | JavaScript ES6 | 221025T151548Z | Arnauld |
| 099 | simply | 221025T141650Z | Ismael M |
| 030 | Pip | 221025T152653Z | Baby_Boy |
| 021 | Pyth | 221025T144218Z | CursorCo |
| nan | Python | 221025T074431Z | mousetai |
| 135 | TSQL | 221025T090009Z | t-clause |
| 013 | 05AB1E | 221025T072434Z | Kevin Cr |
AWK, 87 bytes
{for(a=$1;sub($2,"",$1);)x++;if(x>$3)for(;$3--;)a=gensub("(.*)("$2")","\\1","g",a)}$0=a
{for(a=$1;sub($2,"",$1);) # count occurrences of key
x++;if(x>$3) # compare to n
for(;$3--;) # count down from n
a=gensub("(.*)("$2")","\\1","g",a)
# regex to drop last
}$0=a # set output
Scala 3, 422 bytes
A port of @mousetail's Python answer in Scala.
Use user-defined rsplit.
422 bytes, it can be golfed more.
Golfed version. Attempt This Online!
def r(s: String, d: String, m: Int) = {
var (r, a, n) = (List[String](), s, m)
while (n > 0) {
a.lastIndexOf(d) match {
case -1 => n = 0; r ::= a; a=""
case p => r ::= a.substring(p + d.size); a = a.substring(0, p); n -= 1
}
}
(if (a.nonEmpty || m == 0) a :: r else r).reverse.toArray
}
def f(s: String, d: String, m: Int) = {
val p = r(s, d, m)
if (p.size > m) p.mkString("").trim else s
}
Ungolfed version. Attempt This Online!
object Main {
def rsplit(string: String, delimiter: String, maxSplits: Int): Array[String] = {
var remainingSplits = maxSplits
var str = string
var result = List[String]()
while (remainingSplits > 0) {
val pos = str.lastIndexOf(delimiter)
if (pos == -1) {
result = str :: result
remainingSplits = 0
str=""
} else {
result = str.substring(pos + delimiter.length) :: result
str = str.substring(0, pos)
remainingSplits -= 1
}
}
if (str.nonEmpty || maxSplits == 0) {
result = str :: result
}
result.toArray
}
def splitAndJoin(string: String, delimiter: String, maxSplits: Int): String = {
val splitParts = rsplit(string, delimiter, maxSplits)
if (splitParts.length > maxSplits) splitParts.mkString("") else string
}
def main(args: Array[String]): Unit = {
// Test cases
println(splitAndJoin("bor tor tor tor", "tor", 2)) // More than maxSplits
println(splitAndJoin("bor tor tor", "tor", 2)) // Exactly equal to maxSplits
println(splitAndJoin("bor tor", "tor", 2)) // Less than maxSplits
}
}
R, 124 109 108 bytes (new)
- -11 and -1 bytes thanks to @pajonk
f=\(S,s,n,`?`=\(x)intToUtf8(rev(utf8ToInt(x))))`if`(sum(el(gregexpr(s,S))|1)>=n&n,f(?sub(?s,"",?S),s,n-1),S)
Edit:
The old version of my golf has incorrectly treated a case, when the substring was matching exactly the end of the string. Therefore I have abandoned the old approach.
In this new version a chain of functions is used to reverse the string as well as the substring, sub is applied n times and then the string get reversed again.
Below is the old version.
R, 100 bytes
\(S,s,n,m=length(V<-el(strsplit(S,s))))
`if`(m>n,paste0(V,c(rep(s,m-1-n),rep("",n+1)),collapse=""),S)
This answer is similar to the answer in Python.
The main string S is splitted by a substring s, and then combined with a same length vector containing a reduced by n number of substrings.
Python 3, 78 bytes
i=input
a=i()
b=i()
c=int(i())
d=a.rsplit(b,c)
print([a,''.join(d)][len(d)>c])
Pretty direct approach using Python 3. Try it online!
Ruby, 64 bytes
->s,u,n,*a{x=s.split(u);l=x.size-n;x[0...l].join(u)+x[l..].join}
Code is mine - I thought split and join would be more efficient, but I will credit Jordan above for the tests and framework.
C (clang), 109 107 112 105 100 bytes
-11 bytes thanks to c--
-2 bytes thanks to ceilingcat
+5 bytes for fixing an error pointed out by JvdV.
f(*a,i,*b,j,n,**r){for(*r=wcsdup(a);i--*n>0;)!bcmp(a+i,b,j)?wcscpy(a+i,a+i+j),n--,i-=j:0;!n?*r=a:0;}
Perl 5, 74 bytes
sub{($_,$s,$n)=@_;$n*2>(@a=split/($s)/)?$_:join'',grep!/$s/||++$n*2<@a,@a}
Shell, 238 236 220 200 199 194 191 186 bytes
(counting the last newline to make the script file containing those commands a real unix text file. Otherwise 185 bytes.)
Can probably be highly optimized, but I found it funny to attempt.
usage: cat Text-cases | this_script , or this_script < Test-cases
sed -e'/^O/N;s,\n,,;s,",,g;s, = ,:,g'|awk -F: '/^St/{I=$2}
/^Su/{S=$2}
/^n/{n=$2
R=s=""
for(i=1;i<=n;i++){R=R sprintf("\\(.*\\)%s",S)
s=s"\\"i}
system("echo "I"|sed -e\"s,"R","s",\"")}'
Explanation:
the sed :
1) put the line following "Output:" at the end of that line
2) takes out the doublequotes
3) replace " = " by ":"
Then the awk:
retrieve (I)nput String,
(S)ubstring,
and (n),
loops on n to construct:
the (r)egex "\(.*\)S\(.*\)S\(.*\)S" (if n==3)
and its (s)ubstitution "\1\2\3"
and use sed to do this search/replace on the (I)nput string.
I used "\n" instead of ";" when I could (in the awk part) as it
is 1 caracter all the same, and is more legible.
Japt v2.0a0, 21 bytes
qW ÔË+WpE>VÃw
qWpUʧV
Input as string, n, substring
v2.0a0 is necessary because v1.4.6 errors if you try to use p this way.
Explanation:
qW ÔË+WpE>VÃw
qW # Split <string> where <substring> appears
Ô # Reverse the array
Ë Ã # For each item in the array:
+ # Append:
Wp # <substring> repeated a number of times equal to:
E>V # The current index is greater than <n>
# (Boolean gets converted to 1 or 0)
w # Reverse the new array
# Store as U
qWpUʧV
q # Turn U into a string by inserting this between each item:
Wp # <substring> repeated a number of times equal to:
UÊ # Length of U (i.e. 1 + number of times <substring> appeared)
§V # Is less than or equal to <n>
# Output that string
I've tried an alternate using ð but the best I got was 25 bytes.
PHP, 75 111 bytes
Okay so... lot of change
+12 bytes for a bug found by @Ismael Miguel where loop keep running if no instance of searched string given (strrpos()===false)
+26 bytes for using $argv instead or pre defined variable as indicated by @Sʨɠɠan
-2 bytes (Hey! an actual upgrade :D) from @Sʨɠɠan who remind me i can just get ride of {} for a single line instruction ^^'
for($s=$argv[1];$argv[3]--&&false!==$c=strrpos($s,$argv[2]);)$s=substr($s,0,$c).substr($s,$c+strlen($argv[2]));
Ruby, 67 61 75 bytes
Updated after clarification by OP, which unfortunately made it longer.
->s,u,n,*a{s.scan(u){a<<$`.size}
a.size<n||eval("s[a.pop,u.size]='';"*n)
s}
Python, 51 bytes
lambda A,B,n:"".join(A.rsplit(B,n*(n<=A.count(B))))
PHP 8.x, 65 bytes
This anonymous function does the replacement, up to $n, and checks how many replacements were made.
If there were fewer than $n replacements made, returns the original string.
fn($F,$S,$N)=>($r=preg_replace("@$S@",'',$F,$N,$x))&&$N>$x?$F:$r;
Due to the use of preg_replace, the substring must be a valid regular expression.
Regular words will always be valid regular expressions, and there's no need to worry about it.
How does it work?
The function preg_replace takes the following arguments:
$pattern- Which will be the substring,$S$replacement- Which is an empty string$subject- The full string,$F$limit- Maximum number of replacements,$N&$count- Variable which will hold the number of replacements made
If $N is higher than $count, returns the full string, otherwise returns the result of the replacement.
Example
$fn=fn($F,$S,$N)=>($r=preg_replace("@$S@",'',$F,$N,$x))&&$N>$x?$F:$r;
echo $fn('Cats do not memeowow, they do meow-ing.', 'meow', 2);
// Should display: Cats do not meow, they do -ing.
You can try this on https://onlinephp.io/c/d08f3
Excel (ms365), 115, 83 bytes
-32 also thanks to @jdt and the idea to split instead of loop.
=LET(a,TEXTSPLIT(A1,,B1),b,ROWS(a),IF(b>C1,CONCAT(IF(SEQUENCE(b)<b-C1,a&B1,a)),A1))
Note: This answer has been edited to no longer loop to remove the substring from the end of the string, but split the input instead. This would now give the appropriate answer for input like 'Cats do meow not memeowow, they do meow-ing.' where 'n=3'.
Red, 89 bytes
func[s t n][reverse t either parse r: reverse copy s[n to remove t to end][reverse r][s]]
Working on a reversed copy of the string, I use parse to remove n times the reversed substring. If parse succeeds, I return the modified string reversed, otherwise - the original string.
Desmos, 169 bytes
S=s.length
L=l.length
I=[L-S...1]
A=I[[(l[i...i+S]-s)^2.totalfori=I]=0]
B=\{n>A.\length:[-L],A[1...n]\}
f(l,s,n)=l[[[0^{(b-B)^2}.maxforb=z-[0...S-1]].maxforz=[1...L]]=0]
Try It On Desmos! - Prettified
\$f(l,s,n)\$ takes in two lists of codepoints, with \$l\$ representing the string and \$s\$ representing the substring, and a positive integer \$n\$, representing the number of substrings to remove. The output is also a list of codepoints.
As you can tell by the byte size of the code, Desmos is not really well suited for problems related with string manipulation (When was using Desmos on a string problem ever a good idea?!?!). Also fun fact, this is my first time using a nested list comprehension in Desmos, which is pretty nice. There's probably a better way of doing that part, but nested list comprehensions look cool :P (to be completely honest, I can't think of any better way to do that lol).
Vyxal s, 11 bytes
O≤[Ẇy?NẎY|_
12 bytes without the flag. Takes substring, text, n
Explained
O≤[Ẇy?NẎY|_
O≤ # is the count of the substring in text less than n?
[ | # if so:
Ẇy # Split text on substring, keeping the delimiter. Then uninterleave - this gives a list of splits and a list of delimiters
?NẎ # Take up to the -nth item of the list of delimiters
Y # Reinterleave the delimiters, which will now be shorter than before. The s flag combines all the pieces into a single sting
|_ # Otherwise, just return the original text
Charcoal, 25 bytes
Nθ≔⪪ηζηF›Lηθ⊞η⪫⮌E⊕θ⊟ηω⪫ηζ
Try it online! Link is to verbose version of code. Takes inputs in the order count, string, substring. Explanation:
Nθ
Input the count as an integer.
≔⪪ηζη
Split the string on the substring.
F›Lηθ
If this results in more than enough pieces, then...
⊞η⪫⮌E⊕θ⊟ηω
... join the last n+1 pieces together.
⪫ηζ
Join the (remaining) pieces with the substring.
Retina 0.8.2, 87 bytes
.+$
$*
(?=.*¶(.+)¶)\1
¶
rT`¶``(?(1)$)(?<-1>¶.*)+(?=¶.+¶(1)+$)
+`¶(.*¶(.+)¶1+$)
$2$1
1G`
Try it online! Takes the string, substring and count on three separate lines. Explanation:
.+$
$*
Convert the count to unary.
(?=.*¶(.+)¶)\1
¶
Replace occurrences of the substring in the string with newlines.
rT`¶``(?(1)$)(?<-1>¶.*)+(?=¶.+¶(1)+$)
Remove the last n newlines from the string if there are in fact that many. (Today I discovered that an empty "to" string in transliteration is treated as _, i.e. delete matching characters.) The r causes the regular expression to be evaluated from right to left, so the lookahead gets processed first (setting $#1), then the newline-matching loop in the middle, then the count check at the beginning.
+`¶(.*¶(.+)¶1+$)
$2$1
Replace (remaining) newlines with the substring.
1G`
Keep only the (final) string.
JavaScript (ES6), 62 bytes
Expects (string, substring, n).
(s,q,n)=>(a=s.split(q))[n]+1?a.map(s=>a[++n]+1?s+q:s).join``:s
Commented
(s, q, n) => ( // s = string, q = substring, n = integer
a = s.split(q) // split s on q and save the result in a[]
// if q appears x times, we get x + 1 entries
// some of these entries may be empty strings (falsy)
// so we do '+ 1' to distinguish between empty and undefined
)[n] + 1 ? // if a[n] is defined:
a.map(s => // for each entry s in a[]:
a[++n] + 1 ? // increment n; if a[n] is still defined:
s + q // append q to s
: // else:
s // leave s unchanged
).join`` // end of map(); join everything back together
: // else:
s // return s unchanged
simply, 99 bytes
Creates an anonymous function that returns the expected result.
The argument order is $full_string, $substring and then $number.
fn($F$S$N)&iff(run&len(&str_split($F$S))>$N&str_rev(&str_replace(&str_rev($F)&str_rev($S)''$N))$F);
How does it work?
First, splits the full string by the substring, and counts the number of elements.
When splitting the string:
- If the substring isn't present, returns 1 element.
- If it is present, returns 1 extra element.
Example:&str_split("abcbdbebf", 'b') -> ["a", "c", "d", "e", "f"]
For 4'b's, returns 5 elements.
If the number of elements is higher than $number, that means there's at least $number substrings in the full string.
The &iff() function is just the same as a ternary operator, in C-like languages.
To remove from the end of the string, I need to reverse the string, since there isn't a way to indicate to remove from the end of the string.
However, it takes an argument that indicates how many times to replace, which means, it will replace up to $number occurrences.
The result is returned automatically, since it is a function without a scope, just like an arrow function in JavaScript.
Ungolfed
Code-y looking:
$fn = fn($full_string, $substring, $num) => &iff(
(call &len(&str_split($full_string, $substring))) > $num,
&str_rev(
&str_replace(
&str_rev($full_string),
&str_rev($substring),
'', $num
)
),
$full_string
);
Pseudo-code looking:
Set $fn to an anonymous function ($full_string, $substring, $num)
Begin.
Set $count to the result of calling &len(Call &str_split($full_string, $substring)).
Return the result of calling &iff(
$count > $num,
Call &str_rev(
Call &str_replace(
Call &str_rev($full_string),
Call &str_rev($substring),
'', $num
)
),
$full_string
).
End.
Pip, 30 bytes
d:a^b#d>c?dZJ(bRL#d-UcALxRLc)a
How?
d:a^b#d>c?dZJ(bRL#d-UcALxRLc)a
a : First arg(string)
b : Second arg(substring)
c : Third arg(n)
d: : Assign d to the result of
a^b : Split a on separator b
? : If
#d>c : Length of d is greater then c
Uc : Increment c
bRL : Repeat b
#d- : Length of d - c times
AL : Append list
x : Empty String
RL : Repeat x
c : c times
dZJ : Zip with iterable d
a : Else return a
Pyth, 21 bytes
s.iJcwz*]zt-lJ*KE>lJK
Explanation
s concatenate the elements of
.i interleave
Jcwz the input string split on the substring (assigned to J) and
]z a singleton list of the substring
* duplicated
t one less than
-lJ the length of J minus
*KE>lJK 0 if substring has less than n occurrences, n otherwise
Python, 66 53 52 bytes
- -1 byte thanks to @92.100.97.109 (though not exactly in the way they intended)
lambda i,j,k:[i,''.join(a:=i.rsplit(j,k))][len(a)>k]
Returning identity when the occurrences are less than N is annoying.
T-SQL 135 bytes
Is not looping to avoid the string being created again "memeowow"
WITH c(z)as(SELECT 1UNION ALL
SELECT charindex(@r,@,z+1)FROM c WHERE z>0)SELECT top(@n)@=stuff(@,z,len(@r),'')FROM
c ORDER BY-z PRINT @
05AB1E, 13 bytes
¡`.gI›I*F«}¹ý
Inputs in the order substring, string, n.
Try it online or verify some more n.
Explanation:
¡ # Split the (implicit) second input-sentence on the (implicit) first substring
` # Pop and push all parts separated to the stack
.g # Get the amount of items on the stack
I› # Check if this is larger than the third input-integer `n`
I* # Multiply it by the third input-integer `n`
F # Loop that many times:
« # Concat the top two parts on the stack together
}¹ý # After the loop: join the stack with the first input substring as delimiter
# (after which the result is output implicitly)
