Regexp Search and Replace for Words with Dash (Hyphen)

Maybe so, but of zero importance at this stage of the design and analysis game.

We’re just at the proof-o’-concept stage based on the narrow scope of the OP.

One problem at a time. Incremental and iterative tweaking of the prototype as Mohammad expands further on his needs/requirements. Refine over time.

Big requirements up front: bleurk.

I’m confused why you would specifically want to exclude capitalizing some text … maybe you’re just trying to draw attention to the hard parts?

I wonder whether a workable solution effectively replaces each hyphen with hyphen-plus-space, then capitalizes as usual, and then re-collapses each hyphen-space combination.

As far as I know, there is no place where hyphen is appropriately followed by a space…

:thinking: … Actually, some people use two hyphens to represent an em-dash — like what sets this phrase apart — so I guess those shorthand em-dashes (--) would need to be corrected before doing any of that handling of actual hyphens (which you’re calling “dash” here).

I don’t understand why the version below doesn’t work. It does the proper thing with the hyphenated words, but strips out sapces. I can fix it with Charlie’s space conversion/restoration process, but I don’t know why that’s necessary.

This is the code:

<$let 
  in="simple-words, some text, to-do"
  pat=(\w)(\w*)(-+)(\w)(\w*)
  rep="[[$1]uppercase[]addsuffix[$2]addsuffix[$3]] [[$4]uppercase[]addsuffix[$5]] +[join[]]"
>

This vanilla JS equivalent works just fine:

"simple-words, some text, to-do".replace(
   /(\w)(\w*)(-+)(\w)(\w*)/gm, 
  (_, a, b, c, d, e) => a.toUpperCase() + b + c + d.toUpperCase() + e 
) //=> "Simple-Words, some text, To-Do"

Can someone explain why spaces – not captured by the regex – are removed with this call to search-replace?

It isn’t the regex stripping out spaces. It is the list widget.

Oh, of course. Thank you.

A post was merged into an existing topic: Dynamic Filters in One Go

Evaluate what is inside the triple curly brackets first.

Say {{{ whatever }}} evaluates to A space B space C

<$list filter = "A B C">

You see why the spaces go away, right?

Say {{{ whatever }}} evaluates to A &nbsp; B &nbsp; C

The spaces go away like before, and then the html space codes get rendered at render time.

Thanks. I got that from your earlier response, and I do understand what you’re doing with the multiple replaces – adding a placeholder for spaces, then replacing that placeholder with &nbps; – but my last two attempts above don’t use the <$list> widget; one uses <$text> and the other uses a <$let> variable. Am I implicitly using <$list>? Or is something else going on?

I’m sure it’s me being dense about syntax again, but I don’t see what’s wrong with them.

The text widget just takes the string coming at it and spits out that string without evaluating it. Curly bracket content gets evaluated, then text widget spits that out as-is.

The list widget takes a string and evaluates it. Curly brackets get evaluated, then the list widget evaluates the result of the curly bracket.

We need double evaluation. Triple curly brackets cause one evaluation, and then list widget causes another evaluation.

The only other widget you can use instead of list widget for second evaluation is the wikify widget. (TW 5.2.3 viewpoinr)

That’s going to take a while to sink in. Thank you very much for your help.

Your code dynamically constructs a string representing a filter expression. Great. You now need to evaluate it as a filter expression.

The first filter evaluation constructs your filter expression, the second evaluates it.

Try this:

<$let 
  in="simple-words, some text, to-do"
  pat=(\w)(\w*)(-+)(\w)(\w*)
  rep="[[$1]uppercase[]addsuffix[$2]addsuffix[$3]] [[$4]uppercase[]addsuffix[$5]] +[join[]]"
>

<$text text={{{
      [<in>search-replace:gm:regexp<pat>,<rep>] :map[subfilter<currentTiddler>]
}}}/>

</$let>
1 Like

BTW, there is no need at all for the ::: stuff in there. That just makes it way easier to debug things, because they stand out more than &nbsp;

For those who don’t care about easy visual things for debugging, the following should work (but I have not tried):

<in>search-replace:g[ ],[&nbsp;]search-replace:gm:regexp<pat>,<rep>] ] }}}

1 Like

But that still strips out spaces. Obviously I can use Charlie’s technique, but I really want something simpler to work. I may simply have to get used to disappointment.

Know TiddlyWiki and think as TiddlyWiki is, and there is no struggle and have no disappointment.

Do not know TiddlyWiki and think as not TiddlyWiki is, and you will struggle and have disappointment.

I am happy as a clam, because I think as TiddlyWiki is, and it works as I think.

You are getting in your own way. Empty your cup.

Yes, I’ve watched Kung Fu Panda a few too many times …

It may not be relevant but when splitting titles or strings to perform operations on them you can use +[join[ ]] containing a space to rejoin them restoring the spaces.

Thank you all, I am really enjoying reading all these wonderful discussions. Actually, this question raised to improve the APA titlecase in Refnotes plugin and I am solving parts of a bigger puzzle where all APA titlecase rules apply one by one.

I also realized the below code works fine:

<$let in="simple-words, some text, to-do">

<$text text={{{
  [<in>split[ ]]
  :map[regexp[-]split[-]titlecase[]join[-]else<currentTiddler>]
  :and[join[ ]]
  }}}
/>

</$let>

This is another version.

  • It makes all words titlecase
  • It only makes the second part titlecase, if it is a major word (has four characters in length)
  • It handles em-dash and where extra dashes are existed
  • It handles multipart hyphenated words like multi-part-word or multi-part--words
\define punc() . , ? ! ; :
\define pat() \w+[-]+\w+(-\w*)?
\define hyphenated-major()  [split[-]last[]split[]]:except[enlist<punc>]:and[join[]length[]compare:number:gt[3]]

\define hyphen() [regexp<pat>filter<hyphenated-major>split[-]titlecase[]join[-]else{!!title}]

<$let in="simple-words, some text, to--do and three---doit">

<$text text={{{
[<in>split[ ]titlecase[]]
:map:flat[subfilter<hyphen>]
:and[join[ ]]

  }}}
/>

</$let>

produces

Simple-Words, Some Text, To--do And Three---Doit

Thanks to the :map filter run prefix where it allows to build pipeline (@saqimtiaz)

A post was merged into an existing topic: Dynamic Filters in One Go