| Bytes | Lang | Time | Link |
|---|---|---|---|
| nan | AArch64 machine code | 250607T030425Z | 鳴神裁四点一号 |
| 039 | AWK | 241028T150842Z | xrs |
| 028 | Uiua | 241028T021139Z | noodle p |
| 054 | J | 241027T233154Z | Conor O& |
| 075 | JavaScript Node.js | 241017T054212Z | tsh |
| 049 | JavaScript Node.js | 241017T060415Z | l4m2 |
| 073 | Python | 241016T122302Z | movatica |
| 099 | Bash | 241017T191033Z | Ivan |
| 093 | Java JDK | 241016T133837Z | mastaH |
| 079 | JavaScript Node.js | 241017T013857Z | Jake |
| 024 | Charcoal | 241016T180034Z | Neil |
| 026 | Retina 0.8.2 | 241016T174935Z | Neil |
| 070 | C gcc | 241016T131230Z | jdt |
| 043 | Perl | 241016T092429Z | Toto |
| 030 | Perl 5 pl | 241016T145635Z | Xcali |
| 021 | Japt | 241016T100808Z | Shaggy |
| 016 | Vyxal | 241016T080412Z | lyxal |
| 022 | 05AB1E | 241016T073412Z | Kevin Cr |
| 068 | Google Sheets | 241016T071528Z | doubleun |
AArch64 machine code, .text: 100 + .data: 6 = 106 bytes
Disassembly of section .text:
0000000000000000 <f-0x4>:
0: 38001509 strb w9, [x8], #1
0000000000000004 <f>:
4: 38401409 ldrb w9, [x0], #1
8: 34000289 cbz w9, 58 <f+0x54>
c: 7101e822 subs w2, w1, #0x7a
10: 3a5a4848 ccmn w2, #0x1a, #0x8, mi // mi = first
14: 1a9f47e2 cset w2, pl // pl = nfrst
18: 4a021422 eor w2, w1, w2, lsl #5
1c: 7101e92a subs w10, w9, #0x7a
20: 3a5a4948 ccmn w10, #0x1a, #0x8, mi // mi = first
24: 1a9f47ea cset w10, pl // pl = nfrst
28: 4a0a152a eor w10, w9, w10, lsl #5
2c: 6b0a005f cmp w2, w10
30: 54fffe81 b.ne 0 <f-0x4> // b.any
34: 1000000a adr x10, 0 <f-0x4>
38: 39000549 strb w9, [x10, #1]
3c: 79400149 ldrh w9, [x10]
40: 78002509 strh w9, [x8], #2
44: 14000002 b 4c <f+0x48>
48: 38001509 strb w9, [x8], #1
4c: 38401409 ldrb w9, [x0], #1
50: 35ffffc9 cbnz w9, 48 <f+0x44>
54: d65f03c0 ret
58: 10000000 adr x0, 0 <f-0x4>
5c: 39000401 strb w1, [x0, #1]
60: 17fffffb b 4c <f+0x48>
Contents of section .data:
0000 283f2900 5f3f (?)._?
Synopsis
adr x0,.L.string
adr x1,.L.char
ldrb w1,[x1]
adr x8,.L.buf // Output
bl f
mov x0,1
adr x1,.L.buf
mov x2,1024
mov x8,64
svc 0
mov x0,0
mov x8,93
svc 0
.data
.L.string: .asciz "Search"
.L.char = 'S'
.bss
.L.buf: .fill 1024
Source
/// fn (x0: [*:0]const u8, w1: u8, x8: [*:0]u8) void
/// Writes result to x8[0..x0.len+4]
/// Expects @intFromPtr(x8) + x0.len < @intFromPtr(x0) or
/// @intFromPtr(x8) >= @intFromPtr(x0) + x0.len
.globl f
1:
strb w9,[x8],1 // Copy input character to output memory
f:
ldrb w9,[x0],1 // Get one input character
cbz w9,.L.NotFound // Is it '\0'?
// w2 := toUpper(w1)
subs w2,w1,'z'
ccmn w2,26,8,mi
cset w2,pl
eor w2,w1,w2,lsl 5
// w10 := toUpper(w9)
subs w10,w9,'z'
ccmn w10,26,8,mi
cset w10,pl
eor w10,w9,w10,lsl 5
cmp w2,w10
b.ne 1b
.L.Found:
adr x10,.L.Found.msg // .ascii "_?"
strb w9,[x10,1] // Replace "?" with found character
ldrh w9,[x10] // Get two characters
strh w9,[x8],2 // Store to output memory
b .L.CopyRest
1:
strb w9,[x8],1
.L.CopyRest:
ldrb w9,[x0],1
cbnz w9,1b
ret
.L.NotFound:
adr x0,.L.NotFound.msg // .asciz "(?)"
strb w1,[x0,1] // Replace "?" with w1 character
b .L.CopyRest
.data
.L.NotFound.msg:
.asciz "(?)"
.L.Found.msg:
.ascii "_?"
How to test
Here is the base64 of my tarball. Save as dist.tar.xz.base64:
/Td6WFoAAATm1rRGBMCDB4BQIQEWAAAAAAAAALC23ivgJ/8De10AMwuKYA5QJwj87SsS4vWGI5bQ
b8vLTTeLwCWMuNzy+otbbIGHc5Fc+wEawk5h+DcwF2OU17apMJXXHpea26zAfUL/eYeRgkiEAuHq
Wd/JABJWTgTxcEQUcvvqieYabc580J40llyn2dxKxG2UAk/Lj95UKwor3cNw5T+5ImnjUUWuWXxN
BamlixXNPLFDk2vMdjoXxIWXYXK+192o0mqUtS+nQnxHloTlKsL3Sxd3hJL/y+kadMnct9i0Hmgo
IHpNegK6h7MuZRwN4Hlr4RAFGdoO2aCunHg6PqTF6KSDgbefM1QTWAq83fHuLI8EHelJzUrSm6+A
TPZNb+6VKt1YIaaO3imEVw5XgHychHswdbJ8jARbRkXG2oxpERhXKbmKYcpNZoovBCt1uiUbAen2
fbsu2Wjng4vt6xENjaUCZ+I4dMXfs3FVCLnPVU3q9o7nlaV5UrwT6iSH3pihgSmkeVnzocWrNWIZ
5EOrHmhxlkVLb4lv08IdU/KPN0VXweXPLzef8i8b8T2EkBeofNhXDoUfSTwION0Ywjjs0hopT466
qd+42c9m22SQioLyijefaV1E2RDUTJis+ewkFE1hzn9jRuDJA8vN7eJXUtUHNfP6pAoxa1OUwZF+
gkrvyJhQgscCrNdWzlV1Nh+i00tdhUrr1DU3iY9x4P8nPzAaqr3ajmGbPjUTCbrAmlNen6Lmd0BD
17jb8dc+AzGZtWmOVB+psqem7j6El8Ld5VBqXyv8tfHo3vRbU2tDnsT+zEO/72LG93VgbgZRYSfx
q9CTbYCQYI9UtrIo50qfe/Cgn3RJuXE2ba8SLcJyvSnD8KTsUHWXivP9jDdiTPKlB5ZniQW5RKIJ
7zyfUvf1DUNlUtpBTMLGzkp3KCZc1ezDW+rpd14MAZxYi6x5m/5VTNLXZ4efuvBAfeIzk6SRiNbe
esfAxDOMjR/HTubgi952tlLAZ+iKZF45+R+rVr6i3FeaXIo0EnW+dj8yMrBwJXC1mOyF/x7Noa6f
w95x7lsUOseVGHq6WueICnNNnZAVYNHzqabrVPqDBbXSd69BBIeoK+7zphYzDgVZ32nq8Bv5uyhi
/o0zJy1AbmY1w4ES1SPmD7aDh4GTnuBVvRbFP5yuZYYz7Au4X8o9SJpZzW9QrOUWLXwMZKus9Jx4
nPDBjApK8vQLx00VVmuAu60AAACuqdWqVROIjgABnweAUAAA0DSgHLHEZ/sCAAAAAARZWg==
Decode it and extract with mode Jx:
$ cat dist.tar.xz.base64 | base64 -d | tar Jxf -
You will have four files:
f.s
main.s
testcases.txt
test.sh
Assembled and link two files with your assembler and linker:
$ as -o f.o f.s && as -o main.o main.s && ld -o main f.o main.o
Now you have an executable. Finally run a test; you will have the following result:
$ ./test.sh | tr -d '\0'
./main Search S
_Search
./main Translate N
Tra_nslate
./main Cut X
Cut(X)
./main Snap 10th 1
Snap _10th
./main Snap 50th 2
Snap 50th(2)
./main Excavate E
_Excavate
./main Cut(X) (
Cut_(X)
./main Cut(X) X
Cut(_X)
./main Cut(X) )
Cut(X_)
./main Cut(X) V
Cut(X)(V)
./main Test q
Test(q)
./main Test )
Test())
History
-4 bytes for position of label f
-4 bytes for toUpper() algorithm improvement
AWK, 39 bytes
$1~$2&&sub($2,"_"$2)||$0=$1"($2)",$0=$1
This only seems to work on gawk, whereas mawk and nawk will throw you an error. Also, it runs on TIO, but prints out gibberish :-p
Uiua, 28 bytes
◌⍥:⊃∈(⊂⊂⊙@_⊃↙↘⊗:)⊃∩⌵⟜$"_(_)"
Try it: Uiua pad
⊃∩⌵⟜$"_(_)" puts on the stack the two uppercased inputs, the first input, and "first(second)".
(⊂⊂⊙@_⊃↙↘⊗:) first index of letter, fork split drop, join with underscore between.
◌⍥:⊃∈ check membership of the (both uppercased previously) letter in the string, flip the two stack items that many times, and pop. (Basically: if member, pop the parenthesis thing, otherwise pop the underscore thing)
J, 54 bytes
(F{.[),](')',~'(',[)`('_',])@.(*@#@])[}.~F=:i.&tolower
I tried for hours to make this feel good. My second attempt, which tried to avoid the F=: assignment, was much longer, even after much golfing:
;(,')',~'(',])&>/@[`(]({.,'_',}.)0>@{[)@.(#@(0>@{[)*@-])i.&tolower
;(,')',~'(',])&>/@[`(]({.,'_',}.)F)@.(#@(F=:0>@{[)*@-])i.&tolower
,(}:,')',~'(',{:)@[`(]({.,'_',}.)}:@[)@.(#@}:@[*@-])i.&tolower
i.&tolower(}:,')',~'(',{:)@]`(({.,'_',}.)}:@])@.(#@}:@]*@-[),
i.&tolower(}:,')',~'(',{:)@]`([({.,'_',}.)}:@])@.(#@}:@]>[),
i.&tolower(}:,')',~'(',{:)@]`([({.,'_',}.)}:@])@.(<#@}:@]),
Agenda is probably not the way to go here, maybe there's more bytes to be saved by a completely different approach.
JavaScript (Node.js), 75 bytes
c=>g=s=>s?s[U='toUpperCase']()[0]==c[U]()?'_'+s:s[0]+g(s.slice(1)):`(${c})`
JavaScript (Node.js), 49 bytes
s=>c=>`${s}(${c})`.replace(/((.).*).\2.$/i,'_$1')
From Arnauld's deleted answer
-7B from tsh
Python, 73 bytes
lambda s,c:[s[:(i:=s.lower().find(c.lower()))]+'_'+s[i:],s+f'({c})'][i<0]
Ungolfed for better understanding:
def f(s,c):
# case insensitive search, return index or -1 if not found
i = s.lower().find(c.lower())
# use the index to select the correct string
# first option, selected if found, inserts a _ at position i
return [s[:i]+'_'+s[i:], s+f'({c})'][i<0]
80 bytes using regexp
- -3 bytes thanx to att
- -6 bytes thanx to CursorCoercer
lambda s,c:(t:=re.sub(r'(?=\u%04X)'%ord(c),'_',s,1,2))+f'({c})'*(s==t)
import re
Exploited regexp mechanics:
'\u%04X'%ord(c): Convert the character to a Unicode escape sequence to prevent special characters breaking the regexp(?=x): Lookahead to match the position beforexre.IGNORECASE = 2: Flag to make matching case-insensitive
87 bytes using partition
def f(s,c):h,d,t=min(map(s.partition,(c*2).title()));return[s+f'({c})',h+'_'+d+t][d>'']
89 bytes using recursion
f=lambda s,c,h='':s and(s[0]in(c*2).title()and(h+'_'+s)or f(s[1:],c,h+s[0]))or h+f'({c})'
Bash, 99 bytes
for((i=0;i<${#1};i++));{ b=${1:i:1};[[ ${b,} =~ ${2,} ]]&&{ echo ${1/$b/_$b};exit;};}
echo "$1($2)"
Bash, 101 bytes With special characters support
for((i=0;i<${#1};i++));{ b=${1:i:1};[[ ${b,} =~ "${2,}" ]]&&{ echo ${1/$b/_$b};exit;};}
echo "$1($2)"
Java (JDK), 93 bytes
(s,c)->s.matches("(?i).*\\Q"+c+"\\E.*")?s.replaceFirst("(?i)(\\Q"+c+"\\E)","_$1"):s+"("+c+")"
JavaScript (Node.js) , 79 bytes
x=>([a,b]=x.split`, `,V=a.indexOf(b))<0?a+` (${b})`:a.slice(0,V)+'_'+a.slice(V)
Charcoal, 24 bytes
≔⌕↥θ↥ηζ¿⊕ζ«…θζ_✂θζ»«θ(η)
Try it online! Link is to verbose version of code. Explanation:
≔⌕↥θ↥ηζ
Case-insensitively find the position of the accelerator in the string.
¿⊕ζ«
If the accelerator was found, then...
…θζ_✂θζ
Output the first half of the string, then a _, then the second half.
»«θ(η)
Otherwise output the string and the accelerator surrounded with ()s.
Alternative solution, also 24 bytes:
≔⌕↥θ↥ηζ⭆θ⁺…_⁼κζι¿‹ζ⁰⪫()η
Try it online! Link is to verbose version of code. Explanation:
≔⌕↥θ↥ηζ
Case-insensitively find the position of the accelerator in the string.
⭆θ⁺…_⁼κζι
Output the string with the match (if any) preceded with _.
¿‹ζ⁰⪫()η
If there was no match than output the accelerator surrounded with ()s.
Retina 0.8.2, 26 bytes
i`((.).*)¶\2
_$1
¶(.)
($1)
Try it online! Takes input on separate lines but link is to test suite that splits on , for convenience. Explanation:
i`((.).*)¶\2
_$1
If a matching character in the string can be found for the accelerator, precede the match with _ and delete the accelerator.
¶(.)
($1)
If the accelerator has not been deleted then wrap it in ()s and join it to the end of the string.
C (gcc), 71 70 bytes
i;f(s,c){printf(i?"%.*s_%s":"%.*s(%s)",i-s,s,i?:c,i=strcasestr(s,c));}
Perl, 43 bytes
$c=pop;$_=pop;s/\Q$c/_$&/i or$_.="($c)";say
- The arguments have to be separated by a space
- If one argument contains sapce, it have to be surrounded by quote
- For example:
Snap 10th, 1should be passed as"Snap 10th" 1
$c=pop; # retrieve the 2nd argument, the character
$_=pop; # retrieve the 1st argument, the string
s/\Q$c/_$&/i # find the character and add _ before, \Q escapes the character in order to work with .
or # OR, if it is not found
$_.="($c)"; # concat the character suround by parenthesis
say # print the modified string
Japt, 21 bytes
There's gotta be a better way.
i'_Uv bVv¹r"_$""({V})
i'_Uv bVv¹r"_$""({V}) :Implicit input of strings U & V
i'_ :Insert "_" in U at index
Uv : Lowercase U
b : First 0-based index of, or -1 if not present
Vv : Lowercase V
¹ :End insert
r :Replace
"_$" : RegEx /_$/
"({V}) : With V interpolated between parentheses
Vyxal, 16 bytes
⇩$⇩₌ḟc[\_Ṁ|_⁰øb+
Maybe something with assign and functions is shorter, but for now, insert works
Explained
⇩$⇩₌ḟc[\_Ṁ|_⁰øb+
⇩$⇩ # Push both inputs lowercased. Stack will be [haystack, needle]
₌ḟc # Push haystack.find(needle), needle in haystack
[ # If needle in haystack (i.e the character is in the string case-insensitive):
\_Ṁ # Insert a "_" at the index (0-indexed)
| # Otherwise:
_ # Pop the index (which will be -1)
⁰øb # Surround the character in ()
+ # And append it to the sentence
💎
Created with the help of Luminespire.
05AB1E, 22 bytes
DlIlk©diD®è'_ì®ǝë"ÿ(ÿ)
Case-insensitive replacing isn't really 05AB1E's strong suit..
Try it online or verify all test cases.
Explanation:
D # Duplicate the first (implicit) input-string
l # Convert the copy to lowercase
Il # Push the second input-character, as lowercase as well
k # Get the first 0-based index of this character in the string
# (or -1 if none were present)
© # Store this index in variable `®` (without popping)
di # If the index is non-negative (aka, not -1):
D # Duplicate the string on the stack again
®è # Pop and get the character at index `®`
'_ì '# Prepend a "_"
®ǝ # Insert it back at index `®`
ë # Else:
"ÿ(ÿ) "# Push string "ÿ(ÿ)", where the first `ÿ` is the string on the stack,
# and the second `ÿ` is the (implicit) second input-character
# (after which the result is output implicitly)
Google Sheets, 68 bytes
=let(t,regexreplace(A1,"(?i)("&B1&")","_$1"),t&if(t=A1,"("&B1&")",))

The formula will "Add an underline before any instance of the char, case-insensitive", as specified, and thus adds multiple underscores when the character appears multiple times.
To only add an underscore before the first instance of the char, use this (74 bytes):
=let(t,regexreplace(A1,"(?i)("&B1&")(.*)","_$1$2"),t&if(t=A1,"("&B1&")",))