How to replace all symbols except numbers and + symbol

Hi. I have string +7 (926) 811-11-21 I want with $filter get string +79268111121
from it. Is it possible?

Yes its quite easy with the search an replace operator. or even just split and join because each time you split you loose the thing you are splitting on. Then you join them back,

<$let string="+7 (926) 811-11-21">

{{{ [<string>split[ ]split[-]split[(]split[)]join[]] }}}

You can also use splitregexp

1 Like

Thank you, Tones. But how can we do it with regexp? https://tiddlywiki.com/#search-replace%20Operator%20(Examples) +7 (926----) 811-11sdsds-21dfdfd

With ChatGPTs help {{{ [<string>splitregexp[\D]join[]] }}} you may want to add the + back

Thank you!
{{{[<string>search-replace:g:regexp[\D],[]]}}}

My simpler version works without the search and replace as well, I tested it.

Both are appropriate.

1 Like

I might write a function for this:

\define disallowed() [^\d\+]
\function digits.only(s) [<s>search-replace:g:regexp<disallowed>,[]]

Then you could use it like this:

{{{ [digits.only[+7 (926) 811-11-21]] }}}

Because our regex uses [ and ], which have other meanings in filters, we have to extract it into a separate disallowed variable. Then we define the function digits.only. Because the name includes a dot (.), we can use it inside filters.

The regex is [^\d\+], which takes the \d (digits) character class and the + symbol – which is escaped with a backslash for technical reasons – into the character class [\d\+], then inverts that class with the initial ^. In the end this means that the regex matches any character but a digit or a +. Then the search-replace operator is configured with the g flag for a global replacement, and this regex. It replaces them with an empty string.

2 Likes

Nice work, Scott, I was thinking about the same approach. I love the functions and custom filter operators.

We are calling these “Custom filter operators”, and “custom filter” seems enough.

I just thought I would rewrite it the way I presented above, as just another way. It saves a few bytes, but that is not important.

\define disallowed() [^\d\+]
\function digits.only(s) [<s>splitregexp<disallowed>join[]]

{{{ [digits.only[+7 (926) 811-11-21]] }}}
  • I suppose this approach is using splitregexp to remove characters according to a regular expressions.
  • What I like about your solution, and mine derived from it, is the regular expressions is closer to a native regular expression, it means its easier to find published regular expressions that can be placed in the definition.

Just for fun, I reduced this further which looks like a useful pattern, one we could use to publish a set of custom filter operators for a range of common string manipulations using native regular expressions.

  • I still have a form of dyslexia when I look at regular expressions.
\function digits.only(s reg:"[^\d\+]") [<s>splitregexp<reg>join[]]

{{{ [digits.only[+7 (926) 811-11-21]] }}}

<$let number="+7 (926) 811-11-21">
{{{ [digits.only<number>] }}}

Despite the above simplifications there are more opportunities to write simplified or feature rich functions to support the use of regular expressions, for example if we assume we most likely apply these to variables we can give the variable name.

\function var.regexp(s reg:"[^\d\+]") [<s>getvariable[]splitregexp<reg>join[]]

<$let number="+7 (926) 811-11-21">

{{{ [var.regexp[number]] }}}

In this example you can also;

  • pass an alternative regular expression
  • Return a plain string <<var.regexp number>>
  • Use macrocall to supply regular expression inline;
    • <$macrocall $name=var.regexp s=number reg="[^\d\+]"/>

[Edited]

General regular expressions strip.regex

\function strip.regexp(string reg:"[^\d\+]") [<string>splitregexp<reg>join[]]
<!-- Strips from a string characters according to the regular expression -->

<$macrocall $name="strip.regexp" string="+7 (926) 811-11-21" reg="[^\d\+]"/>
  • In this example one can provide the sting and regular expressions as literals “inline” or any other kind of reference, variable, field, transclusion etc…

I would like to see a few more utility functions like this which allow native regular expressions to be used.

  • Can a regular expression “wizard” resolve the issue of when and how we would use the flag list;
    • flag-list: g for global mode to replace all matches, i for case-insensitive mode, Introduced in v5.2.0 m for multiline mode, “gim” for all. (optional)

Very nice stuff!

I think even most regular (erm, so to speak) regex users feel the same way. They are powerful and concise, but also often very obscure.

I feel as though you answered your own question. g means that it will replace all matches rather than just the first one, i if you want "dog", "Dog", "DOG", etc. to all be compared equal to "dOg". And m is to override the usual behavior of only checking within a single line.

But, can this be used without changing to the search and replace?

  • Perhaps the default is sufficient for most cases?