38
\$\begingroup\$

Write a program or function which receives as input a string representing a Welsh word (UTF-8 unless otherwise specified by you).

The following are all single letters in Welsh:

a, b, c, ch, d, dd, e, f, ff, g, ng, h, i, j, l, ll, m, n, o, p, ph, r, rh, s, t, th, u, w, y

To quote Wikipedia,

While the digraphs ch, dd, ff, ng, ll, ph, rh, th are each written with two symbols, they are all considered to be single letters. This means, for example that Llanelli (a town in South Wales) is considered to have only six letters in Welsh, compared to eight letters in English.

These letters also exist in Welsh, though they are restricted to technical vocabulary borrowed from other languages:

k, q, v, x, z

Letters with diacritics are not regarded as separate letters, but your function must accept them and be able to count them. Possible such letters are:

â, ê, î, ô, û, ŷ, ŵ, á, é, í, ó, ú, ý, ẃ, ä, ë, ï, ö, ü, ÿ, ẅ, à, è, ì, ò, ù, ẁ

(This means that ASCII is not an acceptable input encoding, as it cannot encode these characters.)

Notes:

  • This is code golf.
  • You do not have to account for words like llongyfarch, in which the ng is not a digraph, but two separate letters. This word has nine letters, but you can miscount it as eight. (If you can account for such words, that's kind of awesome, but outside the scope of this challenge.)
  • The input is guaranteed to have no whitespace (unless you prefer it with a single trailing newline (or something more esoteric), in which case that can be provided). There will certainly be no internal whitespace.

Test cases:

  • Llandudno, 8
  • Llanelli, 6
  • Rhyl, 3
  • Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch, 50 (really 51, but we'll count 50)
  • Tŷr, 3
  • Cymru, 5
  • Glyndŵr, 7
\$\endgroup\$
12
  • 4
    \$\begingroup\$ Can the input be given in all lowercase? \$\endgroup\$ Sep 12, 2016 at 17:11
  • 16
    \$\begingroup\$ My wife who is a native Welsh speaker would recommend that the J is added into the "Borrowed" letters section as it isn't actually part of the Welsh alphabet \$\endgroup\$ Sep 12, 2016 at 20:29
  • 1
    \$\begingroup\$ @RichStarkie The Wikipedia article was a little vague on that front. My understanding is that j is used in borrowed words even when it's not present in the original word, so it's used phonologically, which implies that at this stage it's natualized into the language. I've seen similar arguments about v in Irish. It's widely considered not to be part of the Irish alphabet, but it exists in some Irish names, such as Ó Cuiv. \$\endgroup\$
    – TRiG
    Sep 12, 2016 at 21:06
  • 1
    \$\begingroup\$ I seem to recall from my Welsh lessons that nh and ngh are single letters, too. As in "fy nhadau" and "yng Nghymru". \$\endgroup\$
    – daiscog
    Sep 13, 2016 at 15:06
  • 4
    \$\begingroup\$ Shame it's too late; that triple-glyphed "ngh" might have made it a little more complicated. \$\endgroup\$
    – daiscog
    Sep 13, 2016 at 15:15

15 Answers 15

16
\$\begingroup\$

Retina, 23 bytes

i`[cprt]h|dd|ff|ng|ll|.

Try it online!

Even moar regex.

\$\endgroup\$
5
  • \$\begingroup\$ It's probably my ignorance of Retina, but where is the outputting of the length of the input text? The documentation on Retina doesn't seem to explain how that's working in the "Try it online!" site. \$\endgroup\$ Sep 13, 2016 at 14:38
  • 2
    \$\begingroup\$ The output is implicit, because the only line is a Match stage, returning the number of matches. Here, the regex matches every Welsh letter. \$\endgroup\$
    – user48538
    Sep 13, 2016 at 15:17
  • \$\begingroup\$ So by that logic, then every answer below where the length is explicitly called in the code can be shortened? \$\endgroup\$ Sep 13, 2016 at 15:29
  • 2
    \$\begingroup\$ @XaeroDegreaz Retina is one of the only languages that automatically counts matches and prints them out. This is how Retina, the language, works. It is not how other languages work, and so those languages need to call their length functions explicitly to get the right output. \$\endgroup\$
    – isaacg
    Sep 13, 2016 at 15:42
  • \$\begingroup\$ Thanks, I understand now. After reading more into the documentation I see the default "Match" stage performs this output. \$\endgroup\$ Sep 13, 2016 at 16:02
7
\$\begingroup\$

05AB1E, 24 23 21 bytes

Code:

u•éÓœ°D¥M™ù>•30B2ô0:g

Explanation:

u                      # Convert the input to uppercase.
 •éÓœ°D¥M™ù>•30B       # Compressed version of CHDDFFNGLLPHRHTH.
                         It convert the text between the •'s from base 214 to
                         base 10 and converts that to base 30.
                2ô     # Split into pieces of 2.
                  0:   # Replace each element that also occurs in the input by 0.
                    g  # Get the length of the processed input.

Uses the CP-1252 encoding. Try it online!

\$\endgroup\$
5
\$\begingroup\$

JavaScript (ES6), 44 bytes

x=>x.match(/[cprt]h|dd|ff|ng|ll|./gi).length

The trivial answer may be the shortest.

\$\endgroup\$
5
\$\begingroup\$

BASH 52 50 (sed + wc) 41

-9 thanks to Jordan

sed -r 's,dd|ff|ng|ll|[cprt]h,1,gi'|wc -m

If uppercase letter are required this needs an i at the end of the sed command. (I left it out because all of the "single letters" in the question are lowercase even though some examples aren't).

\$\endgroup\$
6
  • 1
    \$\begingroup\$ Why grep -o .|wc -l instead of wc -c? \$\endgroup\$
    – Jordan
    Sep 13, 2016 at 5:04
  • \$\begingroup\$ wc -c counts â through ẁ as two. \$\endgroup\$
    – Riley
    Sep 13, 2016 at 12:27
  • \$\begingroup\$ Ah, of course. FWIW if you use GNU or BSD wc you can use -m to count characters instead of bytes. \$\endgroup\$
    – Jordan
    Sep 13, 2016 at 12:56
  • \$\begingroup\$ Can you move the c from ch in with the [prt]? sed -r 's,dd|ff|ng|ll|[cprt]h,1,gi'|wc -m \$\endgroup\$
    – daiscog
    Sep 13, 2016 at 15:15
  • 2
    \$\begingroup\$ It's a shame ([dfl])\1 would longer than dd|ff|ll. Just one more doubled-consonant would favour the clever version. \$\endgroup\$ Nov 11, 2016 at 14:51
4
\$\begingroup\$

Straw, 30 58 35 33 bytes

<((?i:[cprt]h|dd|ff|ng|ll|.))0/$>

Replace each occurence of the regex by 0, and convert from unary to decimal.

Sadly, Straw can't pass flags to regexs. I forget about the ?flags: construct

Try it online! (The added code is to verify all test cases)

\$\endgroup\$
2
  • \$\begingroup\$ How does this language differ from something like Retina? \$\endgroup\$
    – Downgoat
    Sep 12, 2016 at 21:33
  • \$\begingroup\$ @Downgoat Straw is stack-based :P \$\endgroup\$ Sep 12, 2016 at 21:34
3
\$\begingroup\$

Python 3, 64 bytes

import re
print(len(re.findall("[cprt]h|dd|ff|ng|ll|.",input())))

Uses regex again

Ideone it!

\$\endgroup\$
3
\$\begingroup\$

PowerShell v2+, 52 50 48 bytes

($args[0]-replace'dd|ff|ng|ll|[prtc]h',0).length

Does a -replace on all the two-symbol-single-letter letters, changes 'em to 0 (done because changing to a non-numeral would require quotes), then gets the .length of the resultant string.

Test cases

PS C:\Tools\Scripts\golfing> 'Llandudno','Llanelli','Rhyl','Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch','Tŷr','Cymru','Glyndŵr'|%{"$_ --> "+(.\how-long-is-a-welsh-word.ps1 $_)}
Llandudno --> 8
Llanelli --> 6
Rhyl --> 3
Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch --> 50
Tŷr --> 3
Cymru --> 5
Glyndŵr --> 7
\$\endgroup\$
2
  • \$\begingroup\$ I'm not familiar with PowerShell, but do you really need the parentheses around [prtc]h? \$\endgroup\$
    – Jordan
    Sep 12, 2016 at 17:38
  • \$\begingroup\$ @Jordan No, I do not. That's not a PowerShell thing, that's a me-not-good-at-regex thing. :D Thanks for the golf! \$\endgroup\$ Sep 12, 2016 at 18:03
2
\$\begingroup\$

V, 31 bytes

Íã[cprt]hüddüffüngüllü./
Dé0@"

Try it online, or Verify all test cases!

This contains some unprintable characters, so here is a hexdump:

0000000: cde3 5b63 7072 745d 68fc 6464 fc66 66fc  ..[cprt]h.dd.ff.
0000010: 6e67 fc6c 6cfc 2e2f 010a 44e9 3040 22    ng.ll../..D.0@"
\$\endgroup\$
2
\$\begingroup\$

PHP , 56 Bytes

<?=preg_match_all("#[cprt]h|dd|ff|ll|ng|.#iu",$argv[1]);
\$\endgroup\$
4
  • 1
    \$\begingroup\$ I believe [dfl]{2} matches df, ld, etc. as well as its intended matches. dd|ff|ll is the same length. \$\endgroup\$ Sep 12, 2016 at 20:14
  • 1
    \$\begingroup\$ I know that your believe is true but I think that your believe s not a type of believe. it looks more than a type of kowledge \$\endgroup\$ Sep 12, 2016 at 20:34
  • 1
    \$\begingroup\$ Instead of echo(space at the end), use <?=, which saves 2 bytes. Also, the $t isn't necessary there, saving you 3 more bytes. \$\endgroup\$ Sep 13, 2016 at 10:57
  • \$\begingroup\$ Thnak You Ismael . I must be more then a little confused that I not remove the $t \$\endgroup\$ Sep 13, 2016 at 11:14
1
\$\begingroup\$

Java 7, 156 73 bytes

Loads of bytes saved thanks to @OlivierGrégoire.

int c(String s){return s.replaceAll("[cprt]h|dd|ff|ng|ll","*").length();}

Ungolfed & test cases:

Try it here.

class M{
  static int c(String s){
    return s.replaceAll("[cprt]h|dd|ff|ng|ll", "*").length();
  }

  public static void main(String[] a){
    System.out.println(c("llandudno"));
    System.out.println(c("llanelli"));
    System.out.println(c("rhyl"));
    System.out.println(c("llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch"));
    System.out.println(c("tŷr"));
    System.out.println(c("cymru"));
    System.out.println(c("glyndŵr"));
  }
}

Output:

8
6
3
50
3
5
7
\$\endgroup\$
4
  • \$\begingroup\$ You import and then you don't use Matcher directly? :o Also, Matcher can be defined in the for loop. \$\endgroup\$ Sep 13, 2016 at 13:03
  • 1
    \$\begingroup\$ I have the strong feeling that return s.replaceAll("[cprt]h|dd|ff|ng|ll","a").length() is way, way shorter. Can't this work? \$\endgroup\$ Sep 13, 2016 at 13:07
  • \$\begingroup\$ Well, yes, it works, and it's 73 bytes for the Java 7 version (int c(String s){return s.replaceAll("[cprt]h|dd|ff|ng|ll","a").length();}). And only 51 for the Java 8 version (s->s.replaceAll("[cprt]h|dd|ff|ng|ll","a").length()). \$\endgroup\$ Sep 13, 2016 at 13:17
  • 1
    \$\begingroup\$ @OlivierGrégoire Thanks. The Matcher was an accident. I had it correctly in the test code, but not in the golfed code.. >.> Your replaceAll works better though, thanks. \$\endgroup\$ Sep 13, 2016 at 13:27
1
\$\begingroup\$

R, 54 bytes

Very similar to the other answers. Matches any of the two character letters and replaces them with @ and subsequently counts the number of characters. Reads input from stdin. Uses the option ignore.case = TRUE (third argument to gsub) to match both upper and lowercase characters.

nchar(gsub("ch|dd|ff|ng|ll|ph|rh|th","@",scan(,""),T))

Bonus

Both gsub and nchar are vectorized which means that this also works on a character vector, e.g.:

v=c("Llandudno","Llanelli","Rhyl","Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch","Tŷr","Cymru","Glyndŵr")
nchar(gsub("ch|dd|ff|ng|ll|ph|rh|th","@",v,T))

produces:

[1]  8  6  3 50  3  5  7
\$\endgroup\$
1
\$\begingroup\$

Perl 6, 36 bytes

+*.comb(/:i.|<[cprt]>h|dd|ff|ng|ll/)

Try it online!

\$\endgroup\$
0
\$\begingroup\$

XQuery, 77 bytes

declare variable$s external;count(tokenize($s,'[cprt]h|ff|dd|ll|ng|.','i'))-1
\$\endgroup\$
0
\$\begingroup\$

tcl, 71

proc L s {string le [regsub -all -nocase ch|dd|ff|ng|ll|ph|rh|th $s @]}

demo

\$\endgroup\$
0
\$\begingroup\$

Perl 5, 35 + 1 (-p) = 36 bytes

s/[cprt]h|dd|ff|ng|ll/a/gi;$_=y///c

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.