How Do I Extract Pieces of Text from a Larger Block Using Regex with a Loop

I just have never gotten the 'for each' thing down.....

I have a master block of text that I will provide at the end of this text.
The block is 12 FAQs, 12 questions and 12 answers.
I want to extract the questions to variables cb01, cb03, cb05, cb07 etc up to cb23
I want to extract the answers to variables cb02, cb04, cb06, cb08 etc up to cb24

I have the regex that will capture the first question and answer.
Capture the question
Capture after a number followed by period, up to the question mark.
(?<=\d.\s)([^?]+)?

Capture the answer:
(?<=?\n\n)([^-]+)

I just can't get it to save to the variables and increment, which I have tried.....

I really appreciate any feedback.

---

1. How often should I deep clean my bedroom for a healthy environment?

To maintain a healthy home, it's best to deep clean your bedroom every three to six months. This helps to reduce dust, allergens, and improve overall air quality.

---

2. What are the best tips for a healthier bedroom environment through deep cleaning?

Some of the best tips include vacuuming carpets and upholstery, washing bedding regularly, and wiping down all surfaces. These practices contribute to a healthier bedroom environment by reducing dust and allergens.

---

3. How can I deep clean my bedroom to improve air quality?

Deep cleaning your bedroom can significantly improve air quality by eliminating dust and allergens. Focus on vacuuming, washing fabrics, and dusting surfaces to enhance the air you breathe at night.

---

4. What are some step-by-step instructions for deep cleaning a bedroom?

To deep clean a bedroom step by step, start by decluttering, washing your bedding, dusting surfaces, and cleaning floors. Don’t forget to vacuum under furniture and sanitize high-touch areas like light switches and door handles.

---

5. Why is it important to deep clean bedroom furniture for a healthier space?

Bedroom furniture collects dust, allergens, and germs over time. Deep cleaning furniture not only prolongs its life but also helps create a cleaner, healthier bedroom environment.

---

6. How can deep cleaning my bedroom help me sleep better?

A cleaner, dust-free bedroom can significantly improve your sleep quality. Deep cleaning your bedroom for better sleep removes allergens and creates a fresh, relaxing space.

---

7. What are the benefits of deep cleaning my bedroom to reduce allergens?

Deep cleaning your bedroom reduces allergens like dust mites and pet dander, leading to fewer allergy symptoms. This is especially important if anyone in your household suffers from allergies or asthma.

---

8. How do I sanitize and disinfect my bedroom properly?

Sanitizing and disinfecting your bedroom involves wiping down surfaces with a disinfectant, washing bedding in hot water, and vacuuming carpets to eliminate germs and allergens.

---

9. How can Muffetta's Housekeeping help with deep cleaning my bedroom for a healthier environment?

Muffetta's Housekeeping offers expert cleaning services to deep clean your bedroom, ensuring a healthier home environment. We use non-toxic products to remove allergens and dust effectively.

---

10. Why is deep cleaning crucial for maintaining good indoor air quality in my bedroom?

Deep cleaning is essential for good indoor air quality because it eliminates dust, dirt, and allergens that accumulate over time. Regular deep cleaning can make a noticeable difference in the air you breathe.

---

11. How can I remove dust and allergens from my bedroom effectively?

To effectively remove dust and allergens, regularly dust all surfaces, vacuum floors and carpets, and wash bedding in hot water. Muffetta's Housekeeping can help with professional bedroom cleaning to ensure thorough results.

---

12. What are some tips for keeping my bedroom dust-free after deep cleaning?

To keep your bedroom dust-free after a deep clean, dust surfaces regularly, change your bedding weekly, and use air purifiers to maintain cleaner air in the room.

---

The last time I answered a question similar to this, other people responded that the person asking the question may not be solving the problem the best way. So this time I'm going to try to solve the problem the right way, (or at least a better way) instead of answering precisely what you are asking for.

In my opinion, the right way is to extract the twelve questions into a single variable (and the 12 answers into a single variable) and then index that variable using newlines as the line separator. This means you need only 2 variables instead of 24.

For example, if you extracted the 12 questions into a variable (called "Questions") that looked like this:

1. How often should I deep clean my bedroom for a healthy environment?
2. What are the best tips for a healthier bedroom environment through deep cleaning?
3. How can I deep clean my bedroom to improve air quality?
4. What are some step-by-step instructions for deep cleaning a bedroom?
5. Why is it important to deep clean bedroom furniture for a healthier space?
6. How can deep cleaning my bedroom help me sleep better?
7. What are the benefits of deep cleaning my bedroom to reduce allergens?
8. How do I sanitize and disinfect my bedroom properly?
9. How can Muffetta's Housekeeping help with deep cleaning my bedroom for a healthier environment?
10. Why is deep cleaning crucial for maintaining good indoor air quality in my bedroom?
11. How can I remove dust and allergens from my bedroom effectively?
12. What are some tips for keeping my bedroom dust-free after deep cleaning?

...then you could access each line like this: %Variable%Questions[3]\n% and instead of using a number like 3 you could also use a variable.

This means you don't need either regex (which can be very difficult sometimes) or "for each loops" to extract the data.

Extracting the questions and answers doesn't require a complicated regex, or even any regex at all, but I would do it this way:

image

There are probably different ways to extract the answer, but this should work:

image

3 Likes

Another approach is to capture the whole thing in the form of a single JSON variable value (let's call it local_qa)

You can then refer to each separate question and answer in a format like:

Question 5:
    %JSONValue%local_qa.5.Q%

Answer 5:
    %JSONValue%local_qa.5.A%

Question 12:
    %JSONValue%local_qa.12.Q%

Answer 12:
    %JSONValue%local_qa.12.A%

JSON for Indexed Questions and Answers.kmmacros (7.5 KB)


Expand disclosure triangle to view JS source
return JSON.stringify(
    kmvar.local_Source.split("---\n\n")
        .reduce((a, x, i) => ({
            ...a,
            [i]: x
                ? x.split("\n\n").reduce(
                    (qa, s, j) => ({
                        ...qa,
                        [0 === j ? "Q" : "A"]: (
                            2 > j ? s : qa.A
                        )
                    }),
                    {}
                )
                : undefined
        }),
            {}
        ),
    null, 2
);
3 Likes

I think you have -- what's stopping you here isn't the "For Each" but dynamic variables (or indirection). You can read more about using those on the Wiki -- or, like me, get as far as "This is a bit complicated" and look for another way to do it :wink:

Two excellent methods already. But, for variety, how about a single variable where each line is the question, then a Tab, then the answer -- you could put the resulting text on the Clipboard then paste into a spreadsheet or a Word table, for example.

QandAs.kmmacros (5.8 KB)

Image

Really though, it all depends on what you want to do with the questions and answers after you've separated and saved them. Some data structures work better for some uses, others for others.

1 Like

And because I really, really, need to practice with JSON, here's @ComplexPoint's idea but done with native KM actions:

QandAs (JSON).kmmacros (9.2 KB)

Image

2 Likes

What is a non-native KM action, incidentally ?

( The ICU Regular Expression language is Turing-incomplete but "native" ? )

1 Like

IMO, one that shells out (instantiation cost) and/or requires knowledge of another programming language.

Yep -- a very personal and arbitrary definition :wink:

2 Likes

Got it.

( So use of the external ICU Regular Expression Language library is also "non-native" :slight_smile: )

PS in this case, a more Maestronic solution (avoiding external languages like Regular Expressions and JavaScript) might involve indexed splits with Keyboard Maestro Variable Arrays.

( and here, custom array delimiters like --- and \n\n )

1 Like

I'm trying to understand your JXA script. How did you achieve that the lines with triple dashes are ignored?

BTW: I want to save gems like these in such a way that I can find them back when I need them :).

I have added this comment:


Not sure if this is the best way to do it, neither if my description is valid/will help me to find this gem next year.

Honestly? Borderline, for me.

Perhaps a better definition of Maestronic (I like that!) would be "is it documented on the KM Wiki?". Basic regex is, as is basic JavaScript and shell. But there's still the instantiation cost of "going elsewhere" -- balanced against improved execution speed compared to using multiple KM actions to achieve the same functionality -- and the obfuscation of burying a routine in JavaScript compared to the visibility of a series of help-file linked KM actions.

I'm in no way saying it's "wrong" to use these things -- they're often the most performant, and sometimes the only, way of solving a problem. And there's the "kewl!" factor :wink: But I think it's good to present Maestronic versions of the same, if only to show that KM itself is amazingly versatile and you don't need to be a JavaScript/AS/shell god to do some awesome things with it.

2 Likes
local_Source.split("---\n\n")

yields an array of strings delimited by (but not including) "---\n\n"

1 Like

I agree, and my two candidates for least Maestronic (let alone "Native" – more ideological than technical) would be:

  1. Search and Replace
  2. Kleene Algebra notation (regular expressions)

The first is a bad match for the second, the second quickly becomes write-only, and combined, they generate more user reports of anguish, puzzlement, and great tracts of wasted time than anything else on these pages :frowning:


Keyboard Maestro variable arrays, with custom delimiters – now those are Maestronic :slight_smile:

2 Likes

As a very basic demo of that, we can immediately refer to each QA pair above by its ordinal index, writing:

QA 3:
%Variable%local_QA[1 + 3]---\n\n%

QA 5:
%Variable%local_QA[1 + 5]---\n\n%

Where the 1+ skips the redundant opening "---"


For the next stage, @troy' s list of variable names may suggest an XY problem (a question about an attempted solution rather than the actual problem being solved), so we may need to back up and ask what the broader context and problem is.

Variable Arrays for Indexed Questions and Answers.kmmacros (5.9 KB)

1 Like

Thank you to everyone who responded!

The goal is to take the block of text and get individual variables for each Q and A.
Starting with zz_cb01 being the first Q and zz_cb02 being the first answer.
zz_cb03 being the second Q and zz_cb04 being the second answer.
I then have a macro that pastes them one at a time upon a trigger being used.

It's not flexible but early on in the problem I opted for hard coding the solution using Search Variable Using Regular Expression.
(?<=1.\s)([^?]+)? is Q1
(?<=2.\s)([^?]+)? is Q3 etc. etc.
1.\s[^?]+?\s*(.+?)\s*--- is A1
2.\s[^?]+?\s*(.+?)\s*--- is A2 etc. etc.

Though that is presumably not an end in itself ? :slight_smile:

What is the problem that you are solving by binding particular question and answer texts to each of those variable names ?

When adding content to our website I always add an FAQ section with 12 questions and 12 answers. After I get the master block generated from an LLM I can then have it 'parsed' out like I am doing. It is then easily pasted one at a time into the FAQ block areas in Elementor via a macro I have that uses the zz_cbxx variables one at a time after the macro is triggered.

Ah -- "constrained by a previous design decision" :wink: The nasty bit of me wants to make you go back and re-write that macro to use an array or two... But no!

QandAs into Many Vars.kmmacros (8.9 KB)

Image

I've used local variables to keep my namespace cleaner. If, as I suspect, you are using globals then after you've run this a couple of times with different cb numbers in the last action to check it works you should a) delete that last action, b) disable/delete the two "Set Variable 'Local_cb...' " actions, and c) enable the two "Set Variable 'cb...' " actions.

2 Likes

LOL LOL,,,, thank you with sheepish grin.....

Should I make another post for the following?
I'd like to get the Alt Texts 1-5 into seperate variables.

I'd like to get the Alt Text 1-5 into seperate variables
I'd like to get the Title Attributes 1-5 into seperate variables and
I'd like to get the Descriptions 1-5 into seperate variables

I have this for getting the first Alt Text but can't get 2-5...

  • Alt Text: (.?)(?=\s- Title Attribute)

LLM is not getting it...

---

Image 1: 01.jpg  
- Filename: 1 bridal-attendant-01.jpg  
- Alt Text: Muffetta Household Staffing Agency bridal attendant assisting during wedding preparation. A bridal attendant helping the bride put on earrings.  
- Title Attribute: Bridal attendant services by Muffetta Household Staffing Agency  
- Description: A bridal attendant helping the bride put on earrings. πŸ‘πŸ‘° Muffetta Household Staffing Agency provides professional bridal attendant services for a perfect wedding day. #muffettastaffing  
- Image Title Attribute: Bridal Attendant Helping Bride with Earrings  

---

Image 2: 02.jpg  
- Filename: 2 bridal-attendant-02.jpg  
- Alt Text: Muffetta Household Staffing Agency bridal attendant assisting during wedding preparation. A bridal attendant assisting the bride with her wedding dress.  
- Title Attribute: Bridal attendant services by Muffetta Household Staffing Agency  
- Description: A bridal attendant assisting the bride with her wedding dress. πŸ‘πŸ‘° Muffetta Household Staffing Agency provides professional bridal attendant services for a perfect wedding day. #muffettastaffing  
- Image Title Attribute: Bridal Attendant Helping Bride with Wedding Dress  

---

Image 3: 03.jpg  
- Filename: 3 bridal-attendant-03.jpg  
- Alt Text: Muffetta Household Staffing Agency bridal attendant assisting during wedding preparation. A luxury wedding venue with elegant pink and white decor.  
- Title Attribute: Bridal attendant services by Muffetta Household Staffing Agency  
- Description: A luxury wedding venue with elegant pink and white decor. πŸ‘πŸ‘° Muffetta Household Staffing Agency provides professional bridal attendant services for a perfect wedding day. #muffettastaffing  
- Image Title Attribute: Elegant Wedding Venue with Pink and White Decor  

---

Image 4: 04.jpg  
- Filename: 4 bridal-attendant-04.jpg  
- Alt Text: Muffetta Household Staffing Agency bridal attendant assisting during wedding preparation. A bridal attendant helping a bride adjust her earrings.  
- Title Attribute: Bridal attendant services by Muffetta Household Staffing Agency  
- Description: A bridal attendant helping a bride adjust her earrings. πŸ‘πŸ‘° Muffetta Household Staffing Agency provides professional bridal attendant services for a perfect wedding day. #muffettastaffing  
- Image Title Attribute: Bridal Attendant Adjusting Bride's Earrings  

---

Image 5: 05.jpg  
- Filename: 5 bridal-attendant-05.jpg  
- Alt Text: Muffetta Household Staffing Agency bridal attendant assisting during wedding preparation. A wedding coordinator preparing decorations for a luxury wedding event.  
- Title Attribute: Bridal attendant services by Muffetta Household Staffing Agency  
- Description: A wedding coordinator preparing decorations for a luxury wedding event. πŸ‘πŸ‘° Muffetta Household Staffing Agency provides professional bridal attendant services for a perfect wedding day. #muffettastaffing  
- Image Title Attribute: Wedding Coordinator Preparing Luxury Event Decor  

---