Skip to main content

pattern matching - Split a Unicode string maintaining uppercase characters



I want to split a string according to a predefined set of substrings (lowercase), though the actual text can contain uppercase characters anyplace. The task is to find the matches, longer preferred over shorter (like "tt" over "t" hence the order of alt) and to maintain upper/lowercase status. Since StringCases has a quirk not being able to correctly recognize some upper/lowercase characters (cf. here), the solution is not trivial.


The following code matches every element in alt correctly, though it also converts everything to lowercase:


alt = "tt" | "t" | "a" | "á";
word = "TtattÁatT";
StringCases[ToLowerCase@word, alt]


{"tt", "a", "tt", "á", "a", "tt"}



The next one, while correctly maintains capital letters, fails to recognize "Á" as the uppercase version of "á" (or of a, see later).



StringCases[word, alt, IgnoreCase -> True]


{"Tt", "a", "tt", "a", "tT"}



The problem here is that StringMatchQ returns False:


StringMatchQ["A", "a", IgnoreCase -> True]       (* ==> True *)
StringMatchQ["Á", "á", IgnoreCase -> True] (* ==> False *)
StringMatchQ["Á", "a", IgnoreCase -> True] (* ==> False *)
StringMatchQ["Á", "á" | "a", IgnoreCase -> True] (* ==> True *)

(* for the record *)
ToLowerCase@"Á" === "á" (* ==> True *)
ToUpperCase@"á" === "Á" (* ==> True *)

I think it actually is a bug, as this behaviour is rather inconsistent. Nevertheless, the next code I came up with to match "Á" fails:


StringCases[word, __?(StringMatchQ[#, alt, IgnoreCase -> True] &), IgnoreCase -> True]


{"Ttatt", "atT"}




It cannot recognize "Á", and it splits by the longest match instead of exact matches.


Is it possible to overcome somehow this issue without explicitly listing all combinations of upper/lowercase letters (like "a"|"A"|"á"|"Á"|"tt"|"tT"|"Tt"|...) or saving and restoring character states (upper/lowercase) manually? There are nice examples how the string patternmatcher can be used effectively, I hope this can be solved as well.


Question


Given a possibly large list of short elementary strings like "tt" | "t" | "a" | "á", how can a larger string be split into elementary substrings with keeping all uppercase letters correctly. For example:


"TtattÁatT" == > {"Tt", "a", "tt", "Á", "a", "tT"}

Answer



You can do the lower case conversion as a condition on the pattern, and thereby retain the original:


StringCases["TtattÁatT", c__ /; MemberQ[List@@alt, ToLowerCase[c]]]



{"Tt", "a", "tt", "Á", "a", "tT"}



Comments

Popular posts from this blog

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...

list manipulation - Selecting multiple columns from a matrix?

Sample data: data = { {{2013, 1, 1}, 24.13, 167.67, 231.82}, {{2013, 1, 2}, 32.15, 170.92, 225.99}, {{2013, 1, 3}, 35.43, 172.68, 221.67}, {{2013, 1, 4}, 36.73, 173.05, 218.32}, {{2013, 1, 5}, 58.19, 165.96, 197.05}, {{2013, 1, 6}, 69.99, 163.50, 187.52}, {{2013, 1, 7}, 71.37, 154.21, 175.58}, {{2013, 1, 8}, 72.51, 149.66, 163.25}}; I want a DateListPlot with three graphs, so for a matrix formed by columns 1 and 2, one for columns 1 and 3, and 1 for columns 1 and 4. At the moment I'm using this code: data2 = Transpose[{data[[All, 1]], data[[All, 2]]}]; data3 = Transpose[{data[[All, 1]], data[[All, 3]]}]; data4 = Transpose[{data[[All, 1]], data[[All, 4]]}]; DateListPlot[{data2, data3, data4}, Joined -> True, Filling -> {3 -> {1}}] but I have a hunch that this can be done more efficiently. I don't like the Transpose s in particular. Any ideas? edit (for extra credit) What if I need to multiply the second column by 2, which in my solution is simp...

plotting - How to draw some 2D curves in a 3D plot?

I want to plot several 2D curves ( Sin[x] at y=0 , Cos[x] at y=1 ) in a 3D plot, what function should i use? f[x_, y_] := Piecewise[{{0, y 0}, {Sin[x], y == 0}}] g[x_, y_] := Piecewise[{{0, y 1}, {Cos[x], y == 1}}] Plot3D[{f[x, y], g[x, y]}, {x, 0, 10}, {y, 0, 10}] doesn't work. Any ideas? Answer ParametricPlot3D[{{Sin[u], 0, u}, {Cos[u], 1, u}}, {u, 0, 20}, BoxRatios -> 1, PlotRange -> {{-2, 2}, {-.5, 2}, {0, 20}}] === update - general thoughts === I've seen the comments to this question and a few other approaches to the waterfall (or wire) plot are given in this question: Plotting several functions . Also I cannot not mention one of my favorite Mathematica blogs - Archery with this post on the story of discovery of 1st pulsar and an its infamous graphics - code is given in the post: