# Details

1. j is converted to i and J to I.
2. u and U at the beginning of words are converted to v and V respectively.
3. v and V at anywhere except the beginning of words are converted to u and U respectively.
4. s is converted to ſ (U+017F) unless at the end of the word or preceded by another s.

# Specs

• A word is defined as a sequence of letters in abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.
• All words will have at least two letters.
• The input will only consist of printable ASCII characters (U+0020 - U+007E).
• There will be no occurrences of more than two consecutive s. That is, sss will not be a substring of the input.

# Testcases

Individual words:

Input       Output
------------------------
Joy         Ioy
joy         ioy
Universe    Vniuerſe
universe    vniuerſe
Success     Succeſs
successfull ſucceſsfull
Supervise   Superuiſe
supervise   ſuperuiſe
Super-vise  Super-viſe
I've        I've
majors      maiors
UNIVERSE    VNIUERSE
0universe   0vniuerſe
0verify     0verify
I0ve        I0ve
_UU_          _VU_
_VV_          _VU_
ss_         ſs_


Whole paragraph:

Input:  Christian Reader, I have for thy use collected this small Concordance, with no small labour. For being to comprise much in little roome, I was to make choyse of the most principall and usefull places, and to rank them under such words as I thought most essentiall and materiall in the sentence, because the scant roome allotted unto me, would not permit that I should expresse them under every word in the verse, as it is the manner in large Concordances.

Output: Chriſtian Reader, I haue for thy vſe collected this ſmall Concordance, with no ſmall labour. For being to compriſe much in little roome, I was to make choyſe of the moſt principall and vſefull places, and to rank them vnder ſuch words as I thought moſt eſsentiall and materiall in the ſentence, becauſe the ſcant roome allotted vnto me, would not permit that I ſhould expreſse them vnder euery word in the verſe, as it is the manner in large Concordances.


The SHA-256 hash of the output of the last testcase is:

5641899e7d55e6d1fc6e9aa4804f2710e883146bac0e757308afc58521621644


# Disclaimer

Medievall orthographie is not that conſtante. Pleaſe do not complayne if you ſhall ſee olde bookes with a different orthographie.

• "You are allowed to use f instead of ſ in the output." So there's basically no incentive to use ſ since it takes more bytes. Aug 6, 2016 at 8:13
• @Fatalize Fair point. Removed that one. Aug 6, 2016 at 8:17
• @LeakyNun Can we then count ſ as 1 byte? Aug 6, 2016 at 8:18
• there is actually incentive in the form of ff being changed to fs in some algorithms if ſ was not used Aug 6, 2016 at 8:20
• Shouldn't Super-vise become Super-viſe? Aug 6, 2016 at 8:59

# SED, 144 140 111 Bytes

saved 29 bytes thanks to NoOneIsHere

-r -e'y/j/i/g;y/J/I/g;s/ u/ v/g;s/ U/ V/g;s/^u/v/g;s/^U/V/g;s/([^s])s(\w)/\1ſ\2/g;s/(\w)v/\1u/g;s/(\w)V/\1U/g'

• You brave, brave soul. Aug 10, 2016 at 22:21
• You can cut many bytes by using only 1 -e. Use ;s inbetween statements. Aug 12, 2016 at 14:32
• I didn't know you could do that. Thanks!! Aug 12, 2016 at 16:03

## Python 3 (128 126 bytes)

import re;lambda k:re.sub("(?<!s)s(?=[a-zA-Z])",'ſ',re.sub("(?i)j|(?<![a-z])u|(?<=[a-z])v",lambda c:chr(ord(c.group())^3),k))


chr(ord(c.group())^3) feels excessive to xor a single-character string, but maybe a real Pythonista can suggest a golf. However, it's very convenient that ^3 suffices to interchange i <-> j and u <-> v.

NB The only thing here which requires Python 3 is the Unicode character: Python 2 complains Non-ASCII character '\xc5' <snip> but no encoding declared.

• You shouldn't use \b since \b uses the definition of a word which includes digits and underscores. Aug 6, 2016 at 9:21
• @LeakyNun, hmm. While I'm looking for a fix, could you please add some test cases? Aug 6, 2016 at 9:24
• @R.Kap. (?i). Aug 6, 2016 at 9:45
• @PeterTaylor Wait, what does that do? Aug 6, 2016 at 9:47
• @R.Kap, it makes the regex case-insensitive. Aug 6, 2016 at 9:48

## Retina, 5554 50 bytes

TjJvViIuU
Ti01uUpvVp[a-z]+
s(s*[a-zA-Z])
ſ$1  Try it online! (The first line enables a linefeed-separate test suite.) # Python 3.5, 124116111118125144 142 bytes: import re;lambda k:re.sub("J|j|(?<![a-zA-Z])[uU]|(?<=[a-zA-Z])[Vv]|(?<!s)s(?=[a-zA-Z])",lambda g:dict(zip('jJuUvVs','iIvVuUſ'))[g.group()],k)  Well, this seems like the perfect job for regular expressions! • You can use J|j instead of [Jj] Aug 6, 2016 at 10:05 # JavaScript (ES6), 154 Using parseInt to identify alphabetic characters. Note: casually but luckily parseInt('undefined',36)|0 is < 0 s=>[...s].map((c,i)=>((n=v(c))-19?n==31&p>9?'uU':n!=30|p>9?c=='s'&s[i-1]!=c&v(s[i+1])>9?'?':c+c:'vV':'iI')[p=n,c<'a'|0],p=0,v=c=>parseInt(c,36)|0).join  Less golfed s=> [...s].map( (c,i)=> ((n=v(c))-19 ?n==31&p>9 ?'uU' :n!=30|p>9 ?c=='s'&s[i-1]!=c&v(s[i+1])>9 ?'ſ' :c+c :'vV' :'iI')[p=n,c<'a'|0], p=0, v=c=>parseInt(c,36)|0 ).join  Test F= s=>[...s].map((c,i)=>((n=v(c))-19?n==31&p>9?'uU':n!=30|p>9?c=='s'&s[i-1]!=c&v(s[i+1])>9?'ſ':c+c:'vV':'iI')[p=n,c<'a'|0],p=0,v=c=>parseInt(c,36)|0).join out=(a,b,c)=>O.textContent+=a+'\n'+b+'\n'+c+'\n\n' ti='Christian Reader, I have for thy use collected this small Concordance, with no small labour. For being to comprise much in little roome, I was to make choyse of the most principall and usefull places, and to rank them under such words as I thought most essentiall and materiall in the sentence, because the scant roome allotted unto me, would not permit that I should expresse them under every word in the verse, as it is the manner in large Concordances.' to='Chriſtian Reader, I haue for thy vſe collected this ſmall Concordance, with no ſmall labour. For being to compriſe much in little roome, I was to make choyſe of the moſt principall and vſefull places, and to rank them vnder ſuch words as I thought moſt eſsentiall and materiall in the ſentence, becauſe the ſcant roome allotted vnto me, would not permit that I ſhould expreſse them vnder euery word in the verſe, as it is the manner in large Concordances.' r=F(ti) out(to==r?'OK':'KO',ti,r) test=Joy Ioy joy ioy Universe Vniuerſe universe vniuerſe Success Succeſs successfull ſucceſsfull Supervise Superuiſe supervise ſuperuiſe Super-vise Super-viſe I've I've majors maiors UNIVERSE VNIUERSE 0universe 0vniuerſe 0verify 0verify I0ve I0ve _UU_ _VU_ _VV_ _VU_ ss_ ſs_ .split('\n').map(t=>{ var [i,o]=t.split(/\s+/),r=F(i) out(o==r?'OK':'KO',i,r) }) #O {width:90%; overflow:auto; white-space: pre-wrap} <pre id=O></pre> ## JavaScript (ES6), 111 bytes s=>s.replace(/[a-z]+/gi,w=>w.replace(/j|J|^u|^U|\Bv|\BV|ss|s(?!$)/g,c=>"iIvVuUſ"["jJuUvVs".search(c)]||"ſs"))


Explanation: Because JavaScript regexp has no lookbehind, I instead break up the string into words, which then allows me to use ^ and \B as negative and positive letter lookbehinds. ss is dealt with by matching separately, with the slightly awkward replacement expression which takes fewer bytes than either replacing only the first character of c or adding an extra s to both strings and using the matching substring.

• c=>"iIvVuUſ"["jJuUvVs".search(c)]||"ſs" is nice. 👍🏻 Aug 6, 2016 at 18:47

## CJam (89 88 bytes)

{32|_'>\'{<*}:A;SqS++3ew{_1="jJuUvVs"#[-4_{_0=A!3*}_{_0=A3*}_{_)A\0='s=>268*}W]=~f^1=}%


Online demo

I never understood why CJam doesn't have regexes, but since it doesn't here's a solution which doesn't use them.

# Ruby, 85 + 1 = 86 bytes

Run with ruby -p (+1 byte for p flag). Takes input on stdin.

gsub(/j|(?<=^|[^a-z])u|(?<=[a-z])v|(?<=^|[^s])s(?=[a-z])/i){\$&.tr"jJsUuVv","iIfVvUu"}


Run the tests on ideone (wrapped in a lambda there because you can't give flags to ideone): http://ideone.com/AaZ8ya