Can we run a regex replace at render time?

I would like to run a regex replace when tiddlers are rendered. Is there some sort of hook that would allow me to do this?

In my case I want to adjust the content of my tiddler to replace plain-text fractions with more attractive versions so that

3/4 cup sugar

becomes

<sup>3</sup>&frasl;<sub>4</sub> cup sugar

which will render as

34 cup sugar

The JS to do this is trivial:

const handleFractions = (s) => 
  s.replace(/\b(\d+)\/(\d+)\b/g, `<sup>$1</sup>&frasl;<sub>$2</sub>`)

and I’m sure converting that to a wikitext version would be simple. But how do I hook it into the rendering routine?

I see Hook: th-rendering-element, which looks vaguely related, but I think what I’m looking for would have to be earlier in the rendering cycle, as I’m looking for something that converts wikitext to wikitext+HTML, before any DOM parse nodes would have been created.

I don’t know if I would want to apply this to all tiddler or just those that match a particular fitler (like perhaps [tag[Recipe]].)

I know I could easily add a macro/procedure to render, say <<frac 3 4>> cup sugar, but I want the text entry to be as simple as possible for users.

Is this easy to do now? Is it possible?

Writing it as a wikirule might work. See https://tiddlywiki.com/#%24%3A%2Fcore%2Fmodules%2Fparsers%2Fwikiparser%2Frules%2Fhorizrule.js for a simple example of a wikirule.

5 Likes

Thank you. That looks too be exactly what I want. I’ll play around with it soon.

Just for completeness and alternative approaches (No I don’t understand your talk of DOM nodes)

  • I assume you are aware of ^^3^^/,,4,, and there are Unicode variables for some simple fractions?

  • Perhaps there are javascript functions designed to help people enter fractions which can also display as desired and even give a decimal result?

    • That is address the bigger picture.
  • Also something like the Latex plugin I believe will also do as asked, as may Evans Formula plugin.

  • I would be inclined to make a Tiddlywiki display macro that sups numbers before a / and subs the number after. <<display "3/4">> you could design it to accept any number and detect when fractions are contained within it. eg store 3/4 or 5 1/2 and reformat if containing / then the user can just enter these values.

    • I will see if I can do this with a smart custom function/operator.
  • Entering the world of decimals however may help with latter summations. You could allow a fraction to be entered but simultaneously convert and set a decimal value.

  • And if we include the “units”, For example if someone selects half a cup it stores it as 125 ml, you can also convert back if needed. 250/125.

  • You could also provide a dropdown for common fractions, from which to preformat and or convert to decimal.

ChatGPT “What are the top fractions used?”

The most commonly used fractions are those that frequently appear in everyday life and are often taught early in mathematics education due to their practical applications. Some of these common fractions include:

  1. 1/2: This fraction represents one-half of a whole and is commonly used in various contexts like measuring ingredients, dividing objects, or understanding time.

  2. 1/4: Representing one-quarter of a whole, this fraction is used in similar contexts as 1/2, especially in cooking or dividing things into smaller portions.

  3. 3/4: This fraction indicates three-quarters of a whole and is another common fraction in daily life, particularly in measuring and cooking.

  4. 1/3 and 2/3: These fractions represent one-third and two-thirds of a whole, respectively, and are commonly used in various measurements.

  5. 1/8, 3/8, 5/8, 7/8: These fractions are often used in cooking and measurement, representing specific portions of a whole.

  6. 1/5, 2/5, 3/5, 4/5: Fractions with the denominator of 5 are also common, especially in scenarios where quantities are divided into fifths.

  7. 1/6 and 5/6: Less common than quarters or thirds, these fractions are still used in various applications, such as statistical analysis or measurement.

  8. 1/9, 2/9, 4/9, 5/9, 7/9, 8/9: These fractions are not as commonly used in everyday life but are essential in certain mathematical contexts.

  9. 1/10: Representing one-tenth of a whole, this fraction is frequently used because of its connection to the decimal system.

  10. 1/12: This fraction is often used in time calculations, as there are 12 months in a year and 12 hours on a clock face.

  11. 1/16 and 1/32: These fractions are typically used in measurement, particularly in fields requiring precise measurements, like carpentry or engineering.

Understanding and being able to work with these fractions is crucial, as they are frequently encountered in daily life, from cooking and time management to more advanced mathematical and scientific applications.

This is a hack for a partial solution, I am confident there are better ways;

\function wrap.it(chars) [addprefix<chars>addsuffix<chars>]
\function display.fraction(value) [<value>split[/]first[]wrap.it[^^]] [[/]] [<value>split[/]last[]wrap.it[,,]] +[join[]]

<<display.fraction "3/4">>

<$wikify name=result text=<<display.fraction "3/4">> output=html><<result>></$wikify>

Gives Snag_4bc76cfd

FYI: In part to avoid using wikify I raised this Why cant we also use the view widget for variables?

It’s not really important here. I simply want to do this at an early enough point in the rendering process.

Thank you. There are many useful options here. In fact, I have considered a number of them, but I’m hoping to make this work in the manner I asked. This is of course for the recipe edition discussed elsewhere. I think it would be useful to allow people to type such fractions naturally but display them more attractively, But that attractive display is not important enough to ask the users to learn anything to achieve the formatting.

It’s quite easy to write a macro for this:

title: $:/community/recipes/proc/frac
tags: $:/tags/Global

\procedure frac(n:"1", d:"2") <sup><<n>></sup>&frasl;<sub><<d>></sub>

or, as you point out, even simpler would be

\procedure frac(n:"1", d:"2") ^^<<n>>^^&frasl;,,<<d>>,,

In either case,

<<frac 1 8>> tsp cream of tartar

would then render as

18 tsp cream of tartar

But the users I’m imagining would prefer to type “1/8 tsp…” and not “<<frac 1 8>> tsp”. In fact, I would rather do so myself.

I’m examining @btheado’s suggestion. It’s a new part of TW for me, so it will take some time. But it looks promising.

1 Like

maybe this would do the trick

http://tiddlystuff.tiddlyspot.com/#ReplacePragma

@Scott_Sauyet I like your use of &frasl;

I am wondering how to pass something like “1 1/2”

Thanks! I’ll check it out soon!

Thanks. I don’t know if I’ve ever had need for it before, but it is pretty… and I should have stopped to realize that of course there’s a Unicode character as well.

I’m on my phone and can’t test to double-check. But it should be just,

1 <<frac 1 2>>

That would work but if a field has the value “1 1/2” I tried to parse it but perhaps its not needed. We will see as the recipes wiki unfolds.

I have a trick I use for my own wiki that leverages the “View Template Body” cascade to highlight the search term I used to open a given tiddler; I think you could make use of it here as well! Here’s a proof-of-concept that defines ViewTemplate/recipe to do the custom rendering, and ViewTemplateBodyFilters/recipes to make sure that template gets used for any tiddlers tagged with “Recipes”: My TiddlyWiki — a non-linear personal web notebook

The way it works is ViewTemplateBodyFilters/recipes uses list-before to get priority over the default view template filter, and defines a filter to select tiddlers with the “Recipes” tag and instructs TiddlyWiki to use ViewTemplate/recipe to render the tiddler. Then, ViewTemplate/recipe grabs the text field, does a search and replace for 3/4 → ¾, and uses the wikify widget to render the result.

3 Likes

Hi hoelzro

Clever solution! I am not sure if the wikify widget is costly here or not!
I expected TW to wikify the result itself.

Oh, that is perfect! I have been under the weather and a bit slow to get to this. I was just getting online to try an earlier suggestion and I find the perfect solution waiting.

Thank you very much!

I don’t know for certain, but I would guess it’s not too bad, since there system has to do something similar anyway.

Perhaps this can also be implemented in a cascade?

Thanks! Sure enough - if I remove the wikify widget and replace <<wikitext>> with <<filteredText>>, that still works!

You mean the list of searches and their replacements, or something else?

Sorry, I don’t recall now, but believe I was hinting at what you said here;

  • I think I mistook this for using $:/tags/ViewTemplate

Of course once fully developed we could use the “Story Tiddler” cascade instead.

1 Like

Thank you Scott, this solution (by hoelzro) is worth documenting. I put a note to myself.
It behaves like a customized tiny parser! I am thinking powerful small tools can be created based on this;-)

1 Like

Oh, interesting - I’ve only ever used the view template body cascade!