Regex is trimming off too many characters - sometimes

Discussion in 'PHP' started by sarahk, Sep 2, 2020.

  1. #1
    I'm trying to create a form builder that my users can use with a homegrown markup inspired by BBCode converting their questions into actual HTML

    I've got a regex "fiddle" up at https://regex101.com/r/5uf7fK/1

    I have two examples
    Name: [TEXT|enter your name here]
    Type of tenancy: [RADIO|This is a periodic tenancy,This tenancy ends on [TEXT|enter date]]
    Code (markup):
    and the regex I'm using is

    preg_match_all("/\[([^\]]*)\]/", $block, $matches);
    PHP:
    So here's what I'm getting

    upload_2020-9-3_15-57-41.png
    Ideally, I'd like to work with the full match result and the first result is good.

    In the second result, my expected output is:

    [RADIO|This is a periodic tenancy,This tenancy ends on [TEXT|enter date]]
    Code (markup):
    but the regular expression trims off the second ]

    Anyone know how I can edit that so that it returns both ] ?
     
    sarahk, Sep 2, 2020 IP
  2. NetStar

    NetStar Notable Member

    Messages:
    2,471
    Likes Received:
    541
    Best Answers:
    21
    Trophy Points:
    245
    #2
    It's not a single RegEx that provides your solution. You could have multiple nested [] tags anywhere within a [] tag.... This *can* get quite complex to parse....

    Your best option is to use a BBCode parsing library and edit accordingly to support your makeshift bbcode.... My suggestion is to use PHP's "BBCode" extension or use a makeshift class that exists and is well tested then edit to your spec.

    IF your "bbcode" is nothing more than replaceable tags or simple blocks of tags you could end up doing something as simple as a preg_replace...

    I have an example but this forum won't accept the code

    Edit: Simple example : https://tehplayground.com/ipevj5c4WOhWYRWl
     
    NetStar, Sep 6, 2020 IP
  3. sarahk

    sarahk iTamer Staff

    Messages:
    28,807
    Likes Received:
    4,534
    Best Answers:
    123
    Trophy Points:
    665
    #3
    Thanks for that. I've ended up allowing checkboxes and radios to have nested fields and used < for them. The name and id structure for the inputs is reasonably complicated so a lot goes on when building them including allowing for replications of groups of inputs. Splitting the radio options into individual bbcode items might have been good but linking them back together, especially when replicated, might have been messy.
     
    sarahk, Sep 6, 2020 IP
  4. JEET

    JEET Notable Member

    Messages:
    3,832
    Likes Received:
    502
    Best Answers:
    19
    Trophy Points:
    265
    #4
    Why are you not using a BB code like this one:

    [text label="Enter your name" required="yes"]
    [radio label="select option" options="abc, xyz, fgh" required="no"]

    This will be much easier to parse with both regex and PHP.
     
    JEET, Sep 6, 2020 IP
  5. sarahk

    sarahk iTamer Staff

    Messages:
    28,807
    Likes Received:
    4,534
    Best Answers:
    123
    Trophy Points:
    665
    #5
    @JEET - that would probably be better. I'll look at what's involved in converting. I'd still need to be able to nest.
     
    sarahk, Sep 6, 2020 IP
    JEET likes this.
  6. JEET

    JEET Notable Member

    Messages:
    3,832
    Likes Received:
    502
    Best Answers:
    19
    Trophy Points:
    265
    #6
    To have something nested, you can try to use a bb code like this one:

    [radio label="something" option="ABC" option="XYZ" option="fgh" required="no"]

    Now your first preg_match will return everything inside brackets,
    and if its a type "radio",
    then do another preg_match to find all "options" inside this.

    I think it might look like this:

    $string= ' this is something [text label="something"] [radio label="radio button" option="ABC" option="FFF" required="no"] and some more';

    preg_match_all( '/\[(.*?)\]/is', $string, $match );
    foreach( $match[1] as $k ){
    if( substr( trim($k), 0, 5 ) == 'radio' ){

    preg_match_all( '/(option\=\")(.*?)(\")/is', $k, $options );
    //list of options is in $options[2]

    }//if ends
    }//foreach ends
     
    JEET, Sep 7, 2020 IP
    sarahk likes this.