8
$\begingroup$

I have a text file which contains lines of the type:

SYMATTR InstName U1

where "1" can be actually a number with 1 to 3 digits.

I want to replace the above line with the following 2 lines:

SYMATTR InstName U1

SYMATTR Value E1={E11} E2={E12} E3={E13} E4={E14} E5={E15} E6={E16} E7={E17} E8={E18}

For this, I wrote the following statement, using regular expressions (text is a string containing the file content):

StringReplace[text, 
 RegularExpression["SYMATTR InstName U(\\d+)"] -> 
  "SYMATTR InstName U$1\nSYMATTR Value E1={E$11} E2={E$12} E3={E$13} \
E4={E$14} E5={E$15} E6={E$16} E7={E$17} E8={E$18}"]

Unfortunately, the above doesn't work because probably it tries to find $11, $12, etc., instead of $1. How can I fix the replacement rule?

When I used grepWin to perform the substitutions I was able to make it work with \11, \12, etc., but this kind of referencing doesn't work in Mathematica. Nor it works putting braces around the backreference, as in ${1}1.

I'm using Mathematica 11.1.


Edit: dirty trick

I've found a (hopefully) temporary solution by first introducing a special character and then removing it:

text = "SYMATTR InstName U17\nSYMATTR InstName U1";
textAnnotated = 
  StringReplace[
   text, {RegularExpression["SYMATTR InstName U(\\d+)"] -> 
     "SYMATTR InstName U$1\nSYMATTR Value E1={E$1\[Alpha]1} E2={E$1\
\[Alpha]2} E3={E$1\[Alpha]3} E4={E$1\[Alpha]4} E5={E$1\[Alpha]5} \
E6={E$1\[Alpha]6} E7={E$1\[Alpha]7} E8={E$1\[Alpha]8}"}];
textAnnotated = 
  StringReplace[textAnnotated, {"\[Alpha]" -> ""}];

(* Output:
SYMATTR InstName U17
SYMATTR Value E1={E11} E2={E172} E3={E173} E4={E174} E5={E175} E6={E176} E7={E177} E8={E178}
SYMATTR InstName U1
SYMATTR Value E1={E11} E2={E12} E3={E13} E4={E14} E5={E15} E6={E16} E7={E17} E8={E18} 
*)

I hope anyway that someone can find a cleaner solution.

$\endgroup$
1

4 Answers 4

4
$\begingroup$

If you use RuleDelayed and break the string up, the replacements will be made before the string is rejoined.

text = "SYMATTR InstName U1";
StringReplace[text, 
 RegularExpression["SYMATTR InstName U(\\d+)"] :> 
  "SYMATTR InstName U$1\nSYMATTR Value E1={E$1" <> "1} E2={E$1" <> 
   "2} E3={E$1" <> "3} E4={E$1" <> "4} E5={E$1" <> "5} E6={E$1" <> 
   "6} E7={E$1" <> "7} E8={E$1" <> "8}"]

It may seem a roundabout way to delimit $n arguments, but it's the second-to-last example in the Regular Expressions tutorial.

$\endgroup$
1
  • $\begingroup$ Ah, nice, I actually tried to break the string up but I didn't think of using RuleDelayed. $\endgroup$ Commented May 1, 2017 at 11:16
8
$\begingroup$

Is this what you want?

StringReplace[
    text
  , pre:("SYMATTR InstName U" ~~ d : DigitCharacter..) :> StringTemplate[
        "`1`\nSYMATTR Value `2`"
    ][pre, StringJoin[StringTemplate["E`1`=`2``1` "][#, d] & /@ Range[8]]]
]
"SYMATTR InstName U1
 SYMATTR Value E1=11 E2=12 E3=13 E4=14 E5=15 E6=16 E7=17 E8=18 "

Sorry I'm not very good with regex.

$\endgroup$
2
  • $\begingroup$ Yes, it works! I have to admit that at the beginning I chose the regex way because I had the search strings ready and already tested, and I'm not very familiar with the Mathematica string pattern syntax. I should probably familiarize more with it. $\endgroup$ Commented Apr 30, 2017 at 22:01
  • 1
    $\begingroup$ @MassimoOrtolano i tried with Regex but not successful ! btw you can use Fold[ StringReplace[#1, #2] &, text, {RegularExpression[ "SYMATTR InstName U(\\d+)"] -> "SYMATTR InstName U$1\nSYMATTR Value E1={E$1\[Alpha]1} E2={E$1\ \[Alpha]2} E3={E$1\[Alpha]3} E4={E$1\[Alpha]4} E5={E$1\[Alpha]5} \ E6={E$1\[Alpha]6} E7={E$1\[Alpha]7} E8={E$\[Alpha]18}", "\[Alpha]" -> ""} ] as a shorthand form of your code $\endgroup$
    – Ali Hashmi
    Commented Apr 30, 2017 at 22:01
4
$\begingroup$

The parsing of Regular Expressions by Mathematica seems to be very strange sometimes, although it is a known fact that referring to captured groups is not well standardized across platforms. In cases like yours, when there is a digit following the numbering group, the engine has to decide how to treat it. Some do intelligently parse it, thus deciding that if the group 10, for example, was defined during expression parsing, then $10 would be treated as a reference to the group 10. If not, then it would consider it a reference to the group 1, followed by the digit 0. Also, some engines allow you to explicitly show what group you want to reference by using ${groupnumber} syntax. None of this works though. Maybe some of the site experts know how this is realized in MMA, but given the limitation, we can still work with regex by preventing StringJoin from evaluation before the replacement is made.

Borrowing from Kuba's answer to reduce the repetition of patterns:

text = "SYMATTR InstName U1";
StringReplace[text, 
  RegularExpression["SYMATTR InstName U(\\d+)"] -> 
    Hold@StringJoin["SYMATTR InstName U$1\nSYMATTR Value ", 
    StringTemplate[StringJoin["E`1`={E$1", "`1`} "]][#, "$1"] & /@ Range[8]]] // ReleaseHold

SYMATTR InstName U1

SYMATTR Value E1={E11} E2={E12} E3={E13} E4={E14} E5={E15} E6={E16} E7={E17} E8={E18}

$\endgroup$
3
  • $\begingroup$ You can simply replace Rule with RuleDelayed in your code, and then you won't need anymore Hold/ReleaseHold. $\endgroup$ Commented May 1, 2017 at 6:16
  • $\begingroup$ @AlexeyPopkov Ah, how could I forget! Absolutely right! $\endgroup$
    – Stitch
    Commented May 1, 2017 at 11:51
  • $\begingroup$ "parsing of Regular Expressions by Mathematica seems to be very strange sometimes": How unusual. $\endgroup$
    – Nat
    Commented May 1, 2017 at 12:54
1
$\begingroup$

using Rule but with Inactive and Activate

text = "SYMATTR InstName U1";

StringReplace[text, RegularExpression["SYMATTR InstName U(\\d+)"] -> 
"SYMATTR InstName U$1\nSYMATTR Value " <> 
 Inactive@Table["E" <> ToString@i <> "={E$1" <> ToString@i <> "} ", {i, 
    Range@8}]] // Activate // Quiet

(* "SYMATTR InstName U1 SYMATTR Value E1={E11} E2={E12} E3={E13} E4={E14} E5={E15} E6={E16} \
E7={E17} E8={E18} " *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.