Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I'm struggling to find the right function in mathematica to isolate specific characters in a string. I have got a formula as string (I imported it from an excelfile) like this:

y = 0.97*x1 + 0.521*x2 - 30.21 - 0.07431*x3 - 0.126*x4 - 0.1939*x5 - 0.361*x6

Now I want to isolate the coefficients, e.g. 0.97,0.521 from the x's and maybe store it seperately, so that I know which coefficients were for which x. I thought this would be easily done and I browsed through the help of mathematica, but I couln't find any example which helps me so far. Maybe some of you can help me out which functions is best for this task?

share|improve this question
1  
CoefficientRules[#, Variables@#] &@ToExpression[str] –  belisarius Jan 30 at 13:53
1  
Coefficient[#, Variables@#] &@ToExpression[str] ... etc –  belisarius Jan 30 at 13:53
add comment

5 Answers 5

up vote 6 down vote accepted

Using the internal expression parser:

string = "y = 0.97*x1 + 0.521*x2 - 30.21 - 0.07431*x3 - 0.126*x4 - 0.1939*x5 - 0.361*x6";

Cases[
  ToHeldExpression[string],
  s_Symbol * Except[_Symbol, n_?NumericQ] :> {HoldForm[s], n},
  {-2}
]
{{x1,0.97}, {x2,0.521}, {x3,-0.07431}, {x4,-0.126}, {x5,-0.1939}, {x6,-0.361}}
  • Note use of HoldForm to keep Symbols unevaluated in case they have values assigned.

  • In this simple case the rule s_Symbol * n_ :> {HoldForm[s], n} could be used but I believe the code above is more robust.

  • ToHeldExpression is a deprecated function but still entirely usable, and more concise than ToExpression[string, InputForm, Hold].

share|improve this answer
add comment

This answer is just for exercise purposes, I would use Coefficient way.

string = "y = 0.97*x1 + 0.521*x2 - 30.21 - 0.07431*x3 - 0.126*x4 - 0.1939*x5 - 0.361*x6";

StringCases[
  StringReplace[string, "- " -> "-"],
  c : NumberString ~~ _ ~~ x : ("x" ~~ DigitCharacter) :> {c, x}]
{{"0.97", "x1"}, {"0.521", "x2"}, {"-0.07431", "x3"}, {"-0.126", "x4"},
 {"-0.1939", "x5"}, {"-0.361", "x6"}}

When there are cases like "+ x2" we need one more replacement:

string = "y = 0.97*x1 + x2 - 30.21 - x3 - 0.126*x4 - 0.1939*x5 - 0.361*x6";

StringCases[
 Fold[StringReplace, string, {s : ("+ " | "- ") ~~ "x" :> s <> "1.*x", "- " -> "-"}]
 ,
 c : NumberString ~~ _ ~~ x : ("x" ~~ DigitCharacter) :> {c, x}]
{{"0.97", "x1"}, {"1.", "x2"}, {"-1.", "x3"}, {"-0.126", "x4"}, 
 {"-0.1939", "x5"}, {"-0.361", "x6"}}
share|improve this answer
    
I assumed that the x's were arbitrary symbols, but of that is not the case this is quite good. However you lost the signs of the coefficients which may not be acceptable; perhaps you could add an alternative that retains them? –  Mr.Wizard Jan 30 at 15:56
    
@Mr.Wizard ok, done. Yes it is not general solution. Also free coefficient is skipped, I don't know if it is acceptable. –  Kuba Jan 30 at 16:04
    
I skipped free coefficients as well because it seemed to me that the OP wanted to pair values. +1 with the correction. –  Mr.Wizard Jan 30 at 16:14
    
@Mr.Wizard Ha, you were not careful enough, it skipped "+ x2" cases too! –  Kuba Jan 30 at 16:51
add comment

There are several ways it might be done. This is one example. Here is something like your string:

str = "y=0.97*x1+0.52*x2-30.21-0.07*x3";

I do not take the full version, since you did not give it in M form, which normally you should have done. Now, let us make a list out of it:

 list = List @@ ToExpression[str]
(* {-30.21, 0.97 x1, 0.52 x2, -0.07 x3}   *)

This list is transformed into required one as follows:

 list /. a_ /; Characters[ToString@a][[1]] == "x" -> 1

(*   {-30.21, 0.97, 0.52, -0.07}  *)

Here is another simple solution based on the assumption that you have always the numeration of x-s monotonously increasing,i.e. the list of three elements will be x1, x2 x3 and not x1, x28, x5. In this case one can do as follows:

   rule = Table[
  ToExpression[ToString[x] <> ToString[i]] -> 1, {i, 1, 
   Length[list] - 1}]

(*  {x1 -> 1, x2 -> 1, x3 -> 1}   *)

and then using the list from the previous solution:

    list /. rule

(*   {-30.21, 0.97, 0.52, -0.07}  *)

That' it. Have fun.

share|improve this answer
    
The problems with this kind of approach are that 1) y gets evaluated, which is an undesirable side effect and also, 2) if the xn already have assigned values in the .nb it fails. That's why I posted my "solutions" as comments in the question –  belisarius Jan 30 at 14:17
2  
@belisarius You need no excuses to post a different solution: the more solutions - the better. I love to learn from others to see possibilities I failed to see myself. –  Alexei Boulbitch Jan 30 at 15:06
    
Identifying problems is quite different from having solutions :) –  belisarius Jan 30 at 15:13
    
Thanks guys, I can work with that. It helps me a lot to see different approaches to a problem btw :) –  holistic Jan 30 at 15:22
add comment

Using jVincent's ContextScope[]

m`str1 = "y = 0.97*x1 + 0.521*x2 - 30.21 - 0.07431*x3 - 0.126*x4 - 0.1939*x5 - 0.361*x6";
ContextScope["m`", {SymbolName /@ Variables@#, 
                    Coefficient[#, Variables@#]} &@ToExpression[str1] // Transpose]
(*
{{"x1", 0.97`}, {"x2", 0.521`}, {"x3", -0.07431`}, 
 {"x4", -0.126`}, {"x5", -0.1939`}, {"x6", -0.361`}}
*)
share|improve this answer
add comment

Since I'm still new to String Patterns here is another entry using StringCases.

string = "y = 0.97*x1 + 0.521*x2 - 30.21 - 0.07431*x3 - 0.126*x4 - 0.1939*x5 - 0.361*x6";

StringCases[string, s : ({" ", " + ", " - "} ~~ NumberString) ~~ "*" ~~ 
   x : ("x" ~~ DigitCharacter ..) :> {x, ToExpression@s}]

Gives:

{{"x1", 0.97}, {"x2", 0.521}, {"x3", -0.07431}, {"x4", -0.126}, {"x5", -0.1939}, {"x6",-0.361}}

Note the use of DigitCharacter .. for situations with variables like x10, x11 etc.

Kuba pointed out that cases like "y = x2" cannot be handled by the above method, so we do some StringReplacement before proceeding:

string2 = "y = 0.97*x1 + x2 - 30.21 - x3 - 0.126*x4 - 0.1939*x5 - 0.361*x6";

Now

rp = StringReplace[string2, " " ~~ x : ("x" ~~ DigitCharacter ..) :> " 1" ~~ "*" ~~ x]

Then as before:

StringCases[rp, s : ({" ", " + ", " - "} ~~ NumberString) ~~ "*" ~~ 
                x : ("x" ~~ DigitCharacter ..) :> {x, ToExpression@s}]
{{"x1", 0.97}, {"x2", 1}, {"x3", -1}, {"x4", -0.126}, {"x5", -0.1939}, {"x6", -0.361}}
share|improve this answer
    
You missed what I've missed: "y = x2" –  Kuba Jan 30 at 17:20
    
@Kuba, Ah, thanks! –  RunnyKine Jan 30 at 17:23
    
@Kube see my edit please. –  RunnyKine Jan 31 at 2:43
    
it seems ok now :) also more tidy than mine +1 –  Kuba Jan 31 at 3:26
    
@Kuba, thanks for looking through it :) –  RunnyKine Jan 31 at 3:45
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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