Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Use of compounded double quotes in a string containing several quotation marks and single quotes

    I think I have a problem understanding compounded double-quotes. I am writing an incorrect code on purpose to show what I need:

    Code:
    local is_foreign {nationality_`n'!="US" & nationality_`n'!="Puerto Rico" & nationality_`n'!=""}
    That is, I need to pass to a local macro called `is_foreign' the string enclosed in the parentheses {..} exactly as it is, including the _`n' and the quotation marks. I tried following the user manual and several existing posts, but I wasn't able to achieve my goal. Is anyone able to help?
    Last edited by Riccardo Valboni; 21 Dec 2020, 09:25.

  • #2
    \`n' will escape macro expansion. The string will be copied as is to the local.
    Code:
    . local is_foreign {nationality_\`n'!="US" & nationality_\`n'!="Puerto Rico" & nationality_\`n'!=""}
    
    . mac list _is_foreign
    _is_foreign:    {nationality_`n'!="US" & nationality_`n'!="Puerto Rico" & nationality_`n'!=""}

    Comment


    • #3
      Bjarte, thanks a lot; seems a perfect solution. A follow-up question; if I type:
      Code:
      mac list is_foreign
      instead of
      Code:
      mac list _is_foreign
      Stata responds that "global macro $is_foreign not found"; so, is `is_foreign' now a global instead of a local macro, and should it be invoked as $is_foreign?
      Last edited by Riccardo Valboni; 21 Dec 2020, 09:58.

      Comment


      • #4
        In addition to Bjarte's excellent advice, it looks like you might be trying to build condition for later use in a Stata command. Since the curley braces will cause a syntax error, you should omit them. Here's a silly example illustrating that (silly in that you would never summarize a variable in this way).

        Code:
        local is_foreign foreign==\`n'
        mac list _is_foreign
        forval n = 0/1 {
          summ price if `is_foreign'
        }

        Comment


        • #5
          Hi Leonardo, absolutely, I will omit the curly brakets in my final code. I used them only in the initial post just to show people what it is that I wanted to pass to `is_foreign'. Thanks for the remark though.

          Comment


          • #6
            Originally posted by Riccardo Valboni View Post
            That is, I need to pass to a local macro called `is_foreign' the string enclosed in the parentheses {..} exactly as it is, including the _`n' and the quotation marks.
            Why do you (think you) need to do this? And, where do you want to pass this local macro?

            Note that Bjarte's solution works only until the macro is referenced again. For example,

            Code:
            capture program drop my_demo
            program my_demo
                display `"`0'"'
            end
            
            local is_foreign {nationality_\`n'!="US" & nationality_\`n'!="Puerto Rico" & nationality_\`n'!=""}
            my_demo `is_foreign'
            yields

            Code:
            . local is_foreign {nationality_\`n'!="US" & nationality_\`n'!="Puerto Rico" & nationality_\`n'!=""}
            
            . my_demo `is_foreign'
            {nationality_!="US" & nationality_!="Puerto Rico" & nationality_!=""}
            Note that the code above fails even before my_demo is executed, as you can see here:

            Code:
            local is_foreign {nationality_\`n'!="US" & nationality_\`n'!="Puerto Rico" & nationality_\`n'!=""}
            local not_a__copy `is_foreign'
            macro list

            Comment


            • #7
              On
              Stata responds that "global macro $is_foreign not found"; so, is `is_foreign' now a global instead of a local macro, and should it be invoked as $is_foreign?
              is_foreign is a local (which can be refered to as global _is_foreign) see the "Global and local macro names" in pdf documentation refered to in -help macro-". To show this from mata (avoiding the expansion of embedded local n):
              Code:
              . mata : st_local("is_foreign")
                {nationality_`n'!="US" & nationality_`n'!="Puerto Rico" & nationality_`n'!=""}
              
              . mata : st_global("_is_foreign")
                {nationality_`n'!="US" & nationality_`n'!="Puerto Rico" & nationality_`n'!=""}

              Comment


              • #8
                Daniel, I have a dataset containing on each row a number of firm shareholders--each row, that is, corresponds to one firm of which a number of people/organizations own shares. For each shareholder, I have name, nationality, type (i.e. whether they are a person, a firm...etc), and the percentage of shares they own. So, the variables are called firm_id, shareholder_name_1, nationality_1, type_1, shares_1, shareholder_name_2, nationality_2, type_2, shares_2, ...etc.

                What I need to do is calculate sums of shares for certain categories of such shareholders, like I may need to calculate the percentage of shares owned by US shareholders (including Puerto Rico). Since it turns out shareholders can be a maximum of 12 different entities, the code I have been using is:

                Code:
                gen domestic_sum=0
                foreach n of numlist 1/12 {
                replace domestic_sum=domestic_sum+share_`n' if nationality_`n'=="US" | nationality_`n'=="Puerto Rico"
                }
                Imagine now, that the conditions after the -if- become more complex, e.g. I need to calculate the sum of shares for shareholders of specific types (e.g. foundations, government agencies) that are based in Anglo-Saxon countries, and own at least X.Y% of shares. At this point, the -if- statement can become annoying write. Therefore, to simplify the coding I would like to save all these conditions into local macros, to be used more easily. To do this, however, I need to be able to save in local macros complex strings which include both double (") and single (`') quotation marks.

                The end result would be the ability to write a code like:

                Code:
                gen specific_group_sum=0
                foreach n of numlist 1/12 {
                replace specific_group_sum=specific_group_sum+share_`n' if  `is_government' & `is_anglo_saxon' & shares_`n'>X.Y
                }
                Where, of course, `is_government' and `is_anglo_saxon' are specified in local macros.
                I hope my explanation is clear. Let me know if it's not, I'll be happy to elaborate.

                Comment


                • #9
                  Thanks for the clarification, Bjarte. Do you think I can use the solution you showed in the context I explained in response to Daniel?

                  Comment


                  • #10
                    Seems it should work for the given code examples in #8. (also, have a look at -help inlist()- ref: nationality_`n'=="US" | nationality_`n'=="Puerto Rico")

                    Comment


                    • #11
                      Thanks!

                      (also, have a look at -help inlist()- ref: nationality_`n'=="US" | nationality_`n'=="Puerto Rico")
                      Unfortunately, I cannot use -inlist()- everywhere because in some cases I need to use exclusion conditions e.g. nationality_`n'!="Italy" & nationality_`n'!="Germany"
                      Last edited by Riccardo Valboni; 21 Dec 2020, 11:37.

                      Comment


                      • #12
                        The -inlist()- can also be negated by -!inlist()-.

                        Comment


                        • #13
                          Some years ago, I have had a discussion with Nick Cox about a similar use-case. The term that was used for what you want was "delayed macro substitution". Nick argued that this practice is never necessary and will often lead to less readable code. I needed about a year or so but since then, I totally agree.

                          Note that

                          Code:
                          gen specific_group_sum=0
                          foreach n of numlist 1/12 {
                              local my_condition ...`n'...
                              replace specific_group_sum = specific_group_sum+share_`n' if `my_condition'
                          }
                          achieves the very same result as delayed substitution but is probably easier to follow because the local holding the condition is defined immediately before it is used.

                          Comment


                          • #14
                            Thanks. I take everything that comes from Nick as precious advice. Nick is right that delayed macro substitution leads to less readable code. In the case in question, I am trying to build up a toolbox of conditions that I need to spell out only once and can then used repeatedly. It would be great if Stata allowed the user to easily store a certain string as is, even when it contains all kinds of symbols, and then reproduce the string later on in a context where such symbols are used to trigger particular functions.

                            Comment


                            • #15
                              Originally posted by Riccardo Valboni View Post
                              In the case in question, I am trying to build up a toolbox of conditions that I need to spell out only once and can then used repeatedly.
                              Then perhaps

                              Code:
                              foreach n of numlist 1/12 {
                                  local my_condition`n' ...`n'...
                              }
                              
                              ...
                              
                              foreach n of numlist 1/12 {
                                  replace specific_group_sum = specific_group_sum+share_`n' if `my_condition`n''
                              }
                              Originally posted by Riccardo Valboni View Post
                              It would be great if Stata allowed the user to easily store a certain string as is, even when it contains all kinds of symbols, and then reproduce the string later on in a context where such symbols are used to trigger particular functions.
                              Personally, I do not believe there are (m)any situations where this is needed. Technically, macro substitution takes place before any command, including local, is called; such functionality would, therefore, require changes to the syntax parser.

                              Edit: The Wishlist would be the best place for your suggestion.
                              Last edited by daniel klein; 22 Dec 2020, 02:45.

                              Comment

                              Working...
                              X