Commit | Line | Data |
---|---|---|
7894831e MW |
1 | package uk.org.distorted.tripe; |
2 | ||
3 | import scala.collection.mutable.ArrayBuffer; | |
4 | ||
5 | object Admin { | |
6 | val RX_ORDINARY = "^[^\\\\'\"\\s]+$".r; | |
7 | val RX_WEIRD = "[\\\\'\"]".r; | |
8 | ||
9 | def quote(v: Seq[String]) = { | |
10 | val b = new StringBuilder; | |
11 | var sep = false; | |
12 | for (s <- v) { | |
13 | if (!sep) sep = true; | |
14 | else b.append(' '); | |
15 | s match { | |
16 | case RX_ORDINARY() => b.append(s); | |
17 | case _ => | |
18 | b.append('"'); | |
19 | b.append(RX_WEIRD.replaceAllIn(s, "\\\\$0")); | |
20 | b.append('"'); | |
21 | } | |
22 | } | |
23 | b.mkString | |
24 | } | |
25 | ||
26 | class InvalidQuotingException(msg: String) extends Exception(msg); | |
27 | ||
28 | def split(s: String): Array[String] = { | |
29 | val ab = new ArrayBuffer[String](); | |
30 | val sb = new StringBuilder; | |
31 | ||
32 | object State extends Enumeration { | |
33 | val BETWEEN, WORD, SQUOTE, DQUOTE = Value; | |
34 | } | |
35 | import State.{Value => _, _}; | |
36 | ||
37 | val n = s.length; | |
38 | ||
39 | def scan(pos: Int, st: State.Value, bs: Boolean) | |
40 | { | |
41 | if (pos >= n) { | |
42 | if (bs) | |
43 | throw new InvalidQuotingException("trailing `\\'"); | |
44 | else if (st == SQUOTE || st == DQUOTE) | |
45 | throw new InvalidQuotingException("unmatched quote"); | |
46 | if (st != BETWEEN) ab += sb.mkString; | |
47 | } else (st, bs, s(pos)) match { | |
48 | case (BETWEEN, false, '\\') => scan(pos + 1, WORD, true); | |
49 | case (_, false, '\\') => scan(pos + 1, st, true); | |
50 | case (SQUOTE, false, ''') | (DQUOTE, false, '"') => | |
51 | scan(pos + 1, WORD, false); | |
52 | case (BETWEEN | WORD, false, ''') => scan(pos + 1, SQUOTE, false); | |
53 | case (BETWEEN | WORD, false, '"') => scan(pos + 1, DQUOTE, false); | |
54 | case (BETWEEN, false, ch) if ch.isWhitespace => | |
55 | scan(pos + 1, st, false); | |
56 | case (WORD, false, ch) if ch.isWhitespace => | |
57 | ab += sb.mkString; sb.clear(); | |
58 | scan(pos + 1, BETWEEN, false); | |
59 | case (BETWEEN, _, ch) => sb.append(ch); scan(pos + 1, WORD, false); | |
60 | case (_, _, ch) => sb.append(ch); scan(pos + 1, st, false); | |
61 | } | |
62 | } | |
63 | scan(0, BETWEEN, false); | |
64 | ab.toArray | |
65 | } | |
66 | ||
67 | def main(args: Array[String]) | |
68 | { | |
69 | if (args.length != 1) println(quote(args)); | |
70 | else for (s <- split(args(0))) println(s); | |
71 | } | |
72 | } |