# Symbol Level pattern matching and rule replacement

I want to parse a Mathematica Notebook to get some information regarding the relative use of symbols.

So first things first:

file = "<some-file>.nb";
nb = FullForm[Import[file, "NB"]] (* if there is a better way to import notebook files without having them evaluate I would be happy to hear it.*)

Notebook[{(...341209412...)}]

wolframSymbols = WolframLanguageData[All, EntityProperty["WolframLanguageSymbol", "Name"]];


Since various content in the Notebook is user defined, I would like to first do some form of replacement along the lines of:

 nbFiltered = ReplaceAll[nb, Except[#]->NotWolfram&/@wolframSymbols]


except what I put above does not work.

Assuming it did, what I would really like to figure out how to do (for starters) is get all instances of "SymbolA[SymbolB":

This would require some form of pattern wolframSymbols~~"["~~wolframSymbols, but more importantly I would like to extract

SymbolA->SymbolB (* if this occurs more than once, then I would like a list of each instance *)


where the valid symbols are Join[wolframSymbols,NotWolfram].

It seems the general consensus (see comments) from StringPattern: Not one of pattern? and Limiting scope of StringPattern to first match for efficiency? is that StringPatterns are not the right approach for this.

So how can I apply this symbol level pattern to extract symbol relations all the while not evaluating the code?

@bdforbes suggestions Verbatim is the key.

and @Mr.Wizard 's solution goes over my head (as often is the case)

except in a different - but similar post - @Mr.Wizard thinks that "I believe that if you want to match a Symbol by its constituent characters that you do need to use string patterns..."

However, unlike the above posts and solutions, I am not trying this on a symbol or a small collection of symbols. I want to do this on all symbols.

• Are you interested in Input and Output cells, or all cells? Are you interested in the expressions or the underlying box structures? Jul 2 '18 at 1:17
• If you just want to parse the Code you don’t really need strong patterns. Just extract the boxes, use ToExpression with Hold in the third argument, and parse naturally via Cases. Almost certainly you’ll need to test against Context and just be sure that if you do that the test function has HoldFirst or similar as an attribute. Jul 2 '18 at 9:39
• @CarlWoll more interested in input cells than output cells, but would do all if it is easier. More interested in the expressions, but would take all (box structure inclusive) if it is easier. Jul 2 '18 at 10:50
• @b3m2a1 I am going to ask for more assistance on that one. I downloaded some .nb files from GitHub. I am then trying to import them via Import[file, "NB"] or NotebookImport[file, "Input"]. In this case, they are not strings (and auto evaluate on import) so ToExpression[nb, <form>, Hold] doesnt work for almost all forms that would be relevant (e.g.InputForm, StandardForm). If I convert to string then try, I get empty array when using cases... for example this is a .nb I have raw.githubusercontent.com/FeynCalc/feyncalc/master/FeynCalc/… Jul 2 '18 at 11:20

You can use NotebookImport to just import the input cells. For example, here are the input cells from the documentation notebook for And:

and = NotebookImport[
FileNameJoin[{
\$InstallationDirectory,
"Documentation",
"English",
"System",
"ReferencePages",
"Symbols",
"And.nb"
}],
"Input"
];
and //Short[#, 3]&


It's not clear to me what you want to extract from these expressions, but I will give an example that sort of fits with your request. First, define a function that determines whether a symbol is a "Mathematica" symbol:

SetAttributes[systemSymbol, {Listable, HoldFirst}]

systemSymbol[Symbol[_String]] = False;
systemSymbol[s_Symbol] := Context[s] === "System"
systemSymbol[_] = False;


This is mostly equivalent to your WolframLanguageData approach, although there are System symbols that are not documented, and hence not in WolframLanguageData. So:

systemSymbol[{And, b}]


{True, False}

Then, we can use Cases to pick out your patterns of interest:

Cases[
and,
p:_Symbol?systemSymbol[_Symbol?systemSymbol, ___] :> Hold[p],
Infinity
] //FullForm


List[Hold[Greater[Pi,3]],Hold[Apply[And,Slot[1]]],Hold[List[True,False]],Hold[List[True,False]],Hold[List[True,False]],Hold[Outer[And,List[True,False],List[True,False]]]]