Skip to content

Feature Request: Add character-level replacement for custom symbols #234

@Dan-Ashby

Description

@Dan-Ashby

Feature Request: Character-level replacement for custom symbols

Problem

The current custom_symbols feature is designed to replace entire variable names with a LaTeX friendly string. In some instances it's desirable to swap out individual characters within a variable name. The existing custom_symbols implementation can achieve this, but it can only swap one matching string:

So, for example, if I wanted to introduce parenthesis into a variable by mapping LB and RB to the left and right parenthesis as below:
handcalcs.set_option("custom_symbols", {'LB': '(','RB': ')'})
This would not yield the desired result:
myvarLB1RB would map to myvar(1RB instead of the desired myvar(1)

This occurs because there's a break statement in the swap_custom_symbols method, which prevents subsequent matches being actioned. This is evidently by design, as - if the user is intending only to match whole 'words', rather than a subset of characters within the word - then the variables could quickly become scrambled if multiple matching substrings were found in the custom_symbols list. For example, if the user entered the following:
custom_symbols = { "V_": "V_{", "dot": "\\cdot" "V_dot": "\\dot{V}", }
Then a variable named V_dot would incorrectly be parsed to V_{dot with the first match, and then V_{\\cdot with the second match. The third (desired) string would never match, as - by the time it's reached - the input variable has been scrambled. Note that this risk already exists in the current implementation.

Proposed Solution

  1. Restrict the existing swap_custom_symbols to only match and swap whole-word matches (currently there's a risk of unintended scrambling, as described above).
  2. Add a new swap_custom_characters function that performs character-level replacement without the break statement, allowing multiple replacements in a single variable name. Having both methods gives the user control over whether to match entire words, or individual characters, increasing flexibility, and reducing the potential for unintended behaviors.

Implementation

I have successfully implemented this feature locally with minimal changes:

  • New swap_custom_characters function (similar to existing swap_custom_symbols)
  • Added to processing pipeline at the end to avoid conflicts (i.e. the characters swaps are made after all other functions have been performed, so as to avoid conflicting with other existing behaviors).
  • New config option custom_characters
  • Maintains full backward compatibility

Use Case

This enables clean mathematical notation, utilising parenthesis, commas, and other restricted characters like.
In my current implementation, I've mapped the valid python characters with UniCodes 718, 719, and 716 to the left and right parenthesis, and the comma, respectively, so that I can generate LaTeX representations as below:
handcalcs.set_option("custom_characters", {'ˎ': '(','ˏ': ')', 'ˌ': ','})

  • phi_1ˎ3ˌ2ˏ$φ_{1(3,2)}$
  • E_c1ˎ2ˏ$E_{c1(2)}$

As a structural engineer, you'll perhaps appreciate these symbols; the first is the creep coefficient and the second is the concrete modulus used for tracking the response of element 1 (the precast deck panels) from time index 2 to 3 in a stepwise time-dependent analysis of a composite prestressed concrete bridge girder.

I appreciate that these could have been mapped more simply with the current implementation, but I've found accurately matching the notation to reference texts really helps with avoiding errors! Plus it appeals to my OCD, obviously! haha

If you're interested I'd be happy to provide the implementation details or create a pull request, though as described above it's really just a duplication of the existing swap_custom_symbols functionality, only without a break.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions