(* ::Package:: *)

(************************************************************************)
(* This file was generated automatically by the Mathematica front end.  *)
(* It contains Initialization cells from a Notebook file, which         *)
(* typically will have the same name as this file except ending in      *)
(* ".nb" instead of ".m".                                               *)
(*                                                                      *)
(* This file is intended to be loaded into the Mathematica kernel using *)
(* the package loading commands Get or Needs.  Doing so is equivalent   *)
(* to using the Evaluate Initialization Cells menu command in the front *)
(* end.                                                                 *)
(*                                                                      *)
(* DO NOT EDIT THIS FILE.  This entire file is regenerated              *)
(* automatically each time the parent Notebook file is saved in the     *)
(* Mathematica front end.  Any changes you make to this file will be    *)
(* overwritten.                                                         *)
(************************************************************************)



(* :Name: EPM`Strings` *)


(* :Book: Essentials of Pogramming in Mathematica *)


(* :Author: Paul Wellin *)


(* :Summary: This package contains the functions defined in Chapter 7 Strings. *)


(* :Context: EPM`Strings` *)


(* :Package Version: 1.0 *)


(* :Copyright: Copyright 2015, Paul R Wellin *)


(* :History: Version 1.0 by Paul Wellin, Dec 2012 *)


(* :Keywords: Abecedarian words, anagram, blanagram, Fibonacci words, text filtering, GC ratio, palindromes, random strings, padding strings, DNA sequence table, string partition, string tally, string transpose, XOR encoding *)


(* :Source: Strings.nb *)


(* :Mathematica Version: 10.3 *)


(* Tested in Mathematica 11.1 *)


Remove[AbecedarianQ,Anagrams,Blanagrams,FibonacciWord,FilterText,FindSubsequence,FindWordsContaining,GCRatio,IncludeCharacters,AllCharacters,WordCharacters,PunctuationOnly,MakeVarList,palindromeQ,Palindromes,RandomString,RowLength,SequenceTable,StringPad,stringPartition,StringPermutations,StringTally,StringTranspose,UcLc,UniqueCharacters,WordPosition,XorEncode]


(* BeginPackage["EPM`Strings`"] *)


AbecedarianQ::usage="AbecedarianQ[\!\(\*
StyleBox[\"word\", \"TI\"]\)] returns True if the characters in \!\(\*
StyleBox[\"word\", \"TI\"]\) are ordered in the sense of their character codes.";


Anagrams::usage="Anagrams[\!\(\*
StyleBox[\"word\", \"TI\"]\)] finds all anagrams of the string \!\(\*
StyleBox[\"word\", \"TI\"]\) in the dictionary.";


Blanagrams::usage="Blanagrams[\!\(\*
StyleBox[\"word\", \"TI\"]\)] returns all blanagrams of \!\(\*
StyleBox[\"word\", \"TI\"]\) in the built-in dictionary.";


FibonacciWord::usage="FibonacciWord[\!\(\*
StyleBox[\"n\", \"TI\"]\)] returns the \*
StyleBox[\(\!\(\*
StyleBox[\"n\", \"TI\"]\)th\)] Fibonacci word created by, starting with the strings \"0\" and \"01\", concatenates the the (\!\(\*
StyleBox[\"n\", \"TI\"]\)-1)st and (\!\(\*
StyleBox[\"n\", \"TI\"]\)-2)nd Fibonacci words.";


FilterText::usage="FilterText[\!\(\*
StyleBox[\"str\", \"TI\"]\)\!\(\*
StyleBox[\",\", \"TI\"]\)\!\(\*
StyleBox[\" \", \"TI\"]\)\!\(\*
StyleBox[\"lis\", \"TI\"]\)] removes all stops words given in the list \!\(\*
StyleBox[\"lis\", \"TI\"]\) from the string \!\(\*
StyleBox[\"str\", \"TI\"]\).";


FindSubsequence::usage="FindSubsequence[\!\(\*
StyleBox[\"num\", \"TI\"]\)\!\(\*
StyleBox[\",\", \"TI\"]\)\!\(\*
StyleBox[\" \", \"TI\"]\)\!\(\*
StyleBox[\"subseq\", \"TI\"]\)] returns the starting and ending positions of the subsequence \!\(\*
StyleBox[\"subseq\", \"TI\"]\)\!\(\*
StyleBox[\" \", \"TI\"]\)in the number \!\(\*
StyleBox[\"num\", \"TI\"]\)\!\(\*
StyleBox[\".\", \"TI\"]\)";


FindWordsContaining::usage="FindWordsContaining[\!\(\*
StyleBox[\"str\", \"TI\"]\)] finds all words in the built-in dictionary that contain the string \!\(\*
StyleBox[\"str\", \"TI\"]\). The option WordPosition\[Rule]\!\(\*
StyleBox[\"pos\", \"TI\"]\) can be used to specify the position of \!\(\*
StyleBox[\"str\", \"TI\"]\). \!\(\*
StyleBox[\"pos\", \"TI\"]\) can be either \"Start\", \"Middle\", \"End\", or \"Anywhere\".";


GCRatio::usage="GCRatio[\!\(\*
StyleBox[\"str\", \"TI\"]\)\!\(\*
StyleBox[\",\", \"TI\"]\)\!\(\*
StyleBox[\" \", \"TI\"]\)\!\(\*
StyleBox[\"blocksize\", \"TI\"]\)] computes the GC ratio in the string \!\(\*
StyleBox[\"str\", \"TI\"]\) for substrings of size \!\(\*
StyleBox[\"blocksize\", \"TI\"]\).";


IncludeCharacters::usage="IncludeCharacters is an option to StringTally. Possible values are AllCharacters, PunctuationOnly, and WordCharacters.";


AllCharacters::usage="AllCharacters is a possible setting for the IncludeCharacters option in StringTally.";


WordCharacters::usage="WordCharacters is a possible setting for the IncludeCharacters option in StringTally.";


PunctuationOnly::usage="PunctuationOnly is a possible setting for the IncludeCharacters option in StringTally.";


MakeVarList::usage="MakeVarList[\!\(\*
StyleBox[\"sym\", \"TI\"]\)\!\(\*
StyleBox[\",\", \"TI\"]\)\!\(\*
StyleBox[\" \", \"TI\"]\)\!\(\*
StyleBox[\"n\", \"TI\"]\)] generates a list of \!\(\*
StyleBox[\"n\", \"TI\"]\) indexed symbols.\nMakeVarList[\!\(\*
StyleBox[\"sym\", \"TI\"]\)\!\(\*
StyleBox[\",\", \"TI\"]\)\!\(\*
StyleBox[\" \", \"TI\"]\)\!\(\*
StyleBox[\"{\", \"TI\"]\)\!\(\*
StyleBox[\"n\", \"TI\"]\)\!\(\*
StyleBox[\",\", \"TI\"]\)\!\(\*
StyleBox[\"m\", \"TI\"]\)\!\(\*
StyleBox[\"}\", \"TI\"]\)] generates a list of indexed symbols from \!\(\*SubscriptBox[
StyleBox[
StyleBox[\"sym\", \"TI\"],\nFontWeight->\"Plain\"], 
StyleBox[\"n\", \"TI\"]]\) to \!\(\*SubscriptBox[
StyleBox[\"sym\", \"TI\"], 
StyleBox[\"m\", \"TI\"]]\).";


If[$VersionNumber<10.3,
PalindromeQ::usage="PalindromeQ[\!\(\*
StyleBox[\"expr\", \"TI\"]\)] returns True of \!\(\*
StyleBox[\"expr\", \"TI\"]\) is palindromic. The expression \!\(\*
StyleBox[\"expr\", \"TI\"]\) can be either a string or a number."]


If[$VersionNumber>=10.3,palindromeQ::usage="palindromeQ[\!\(\*
StyleBox[\"expr\", \"TI\"]\)] returns True of \!\(\*
StyleBox[\"expr\", \"TI\"]\) is palindromic. The expression \!\(\*
StyleBox[\"expr\", \"TI\"]\) can be either a string or a number."]


Palindromes::usage="Palindromes[] returns all palindromes from the dictionary the comes with \!\(\*
StyleBox[\"Mathematica\",\nFontSlant->\"Italic\"]\).\nPalindromes[\!\(\*
StyleBox[\"n\", \"TI\"]\)] returns all palindromes of length \!\(\*
StyleBox[\"n\", \"TI\"]\).";


RandomString::usage="RandomString[\!\(\*
StyleBox[\"{\", \"TI\"]\)\!\(\*SubscriptBox[
StyleBox[\"c\", \"TI\"], \(1\)]\),\!\(\*SubscriptBox[
StyleBox[\"c\", \"TI\"], \(2\)]\),\[Ellipsis],\!\(\*SubscriptBox[
StyleBox[\"c\", \"TI\"], \(n\)]\)}] generates a random string of length \!\(\*
StyleBox[\"n\", \"TI\"]\) from among the characters \!\(\*SubscriptBox[
StyleBox[\"c\", \"TI\"], \(i\)]\) chosen at random. The option Weights can be used to give weighted choices of the characters.\nRandomString[\!\(\*
StyleBox[\"{\", \"TI\"]\)\!\(\*
StyleBox[\"list\", \"TI\"]\),{\!\(\*SubscriptBox[
StyleBox[\"n\", \"TI\"], 
StyleBox[\"1\", \"TR\"]]\),\!\(\*SubscriptBox[
StyleBox[\"n\", \"TI\"], 
StyleBox[\"2\", \"TR\"]]\),\!\(\*
StyleBox[\"\[Ellipsis]\", \"TR\"]\)}] generates an \!\(\*SubscriptBox[
StyleBox[\"n\", \"TI\"], 
StyleBox[\"1\", \"TR\"]]\)\[Times]\!\(\*SubscriptBox[
StyleBox[\"n\", \"TI\"], 
StyleBox[\"2\", \"TR\"]]\)\[Times]\[Ellipsis] array of random strings.";


RandomString::badwt="The list of weights should have the same length as the list of strings.";


RowLength::usage="RowLength is an option to SequenceTable that specifies the number of blocks in each row.";


SequenceTable::usage="SequenceTable[\!\(\*
StyleBox[\"lis\", \"TI\"]\)] returns a formatted table suitable for displaying gene sequences. SequenceTable inherits options from Grid.";


StringPad::usage="StringPad[\!\(\*
StyleBox[\"str\", \"TI\"]\),\!\(\*
StyleBox[\"n\", \"TI\"]\)] pads string \!\(\*
StyleBox[\"str\", \"TI\"]\) out to length \!\(\*
StyleBox[\"n\", \"TI\"]\) with whitespace.\nStringPad[\!\(\*
StyleBox[\"str\", \"TI\"]\),{\!\(\*
StyleBox[\"n\", \"TI\"]\)}] appends \!\(\*
StyleBox[\"n\", \"TI\"]\) whitespace characters to the end of \!\(\*
StyleBox[\"str\", \"TI\"]\).";


StringPad::badlen="Pad length `1` must be greater than the length of string `2`.";


stringPartition::usage="stringPartition[[\!\(\*
StyleBox[\"list\", \"TI\"]\),\!\(\*
StyleBox[\"n\", \"TI\"]\)] partitions \!\(\*
StyleBox[\"list\", \"TI\"]\) into non-overlapping sublists of strings of length \!\(\*
StyleBox[\"n\", \"TI\"]\). stringPartition has the same argument structure as Partition.";


StringPermutations::usage="StringPermutations[[\!\(\*
StyleBox[\"str\", \"TI\"]\)] returns all permutations of the string \!\(\*
StyleBox[\"str\", \"TI\"]\).";


StringTally::usage="StringTally[\!\(\*
StyleBox[\"str\", \"TI\"]\)] tallys the occurrences of each character in the string str. The option IncludeCharacters can take on values AllCharacters (the default), WordCharacters, or PunctuationOnly to restrict the types of characters that are tallied.";


StringTally::badopt="The option value IncludeCharacters can only take on the following values: All, LetterCharacters, WordCharacters, PunctuationOnly.";


StringTranspose::usage="StringTranspose[\!\(\*SubscriptBox[
StyleBox[\"str\", \"TI\"], \(1\)]\)\!\(\*
StyleBox[\",\", \"TI\"]\)\!\(\*
StyleBox[\" \", \"TI\"]\)\!\(\*SubscriptBox[
StyleBox[\"str\", \"TI\"], \(2\)]\)] transposes the characters in the two strings \!\(\*SubscriptBox[
StyleBox[\"str\", \"TI\"], \(1\)]\) and \!\(\*SubscriptBox[
StyleBox[\"str\", \"TI\"], \(2\)]\) returning the concatenated result.";


UcLc::usage="UcLc[\!\(\*
StyleBox[\"str\", \"TI\"]\)] converts the first character in the string \!\(\*
StyleBox[\"str\", \"TI\"]\) to uppercase.";


UniqueCharacters::usage="UniqueCharacters[\!\(\*
StyleBox[\"str\", \"TI\"]\)] returns a list of unique characters in the string \!\(\*
StyleBox[\"str\", \"TI\"]\), deleting duplicates.";


WordPosition::usage="WordPosition is an option to FindWordsContaining that determines where the target string occurs. Possible values are \"Start\", \"Middle\", \"End\", or \"Anywhere\".";


XorEncode::usage="XorEncode[\!\(\*
StyleBox[\"text\", \"TI\"]\)\!\(\*
StyleBox[\",\", \"TI\"]\)\!\(\*
StyleBox[\" \", \"TI\"]\)\!\(\*
StyleBox[\"key\", \"TI\"]\)] encodes \!\(\*
StyleBox[\"text\", \"TI\"]\) using an Xor cipher with key \!\(\*
StyleBox[\"key\", \"TI\"]\).";


Options[FindWordsContaining]={WordPosition->"Start"};


Options[RandomString]={Weights->{}};


Options[SequenceTable]=Join[{BlockSize->12,RowLength->5},Options[Grid]];


Options[StringTally]={IncludeCharacters->AllCharacters,IgnoreCase->False};


Begin["`Private`"];


AbecedarianQ[word_String]:=OrderedQ[ToCharacterCode[word]]


Anagrams[word_String]:=Module[{len=StringLength[word],words},
words=DictionaryLookup[RegularExpression["\\w{"<>ToString[len]<>"}"]];
Select[words,Sort[Characters[#]]==Sort[Characters[word]]&]
]


Blanagrams[word_String]:=Module[{blana},
blana=Table[
Map[StringReplacePart[word,ch,{#,#}]&,Range[StringLength[word]]],
{ch,CharacterRange["a","z"]}];
DeleteDuplicates[Flatten[Map[Anagrams,blana,{2}]]]
]


FibonacciWord[1]="0";
FibonacciWord[2]="01";


FibonacciWord[n_]:=FibonacciWord[n-1]<>FibonacciWord[n-2]


FilterText[str_String,stopwords_List]:=Module[{tmp},
tmp=StringSplit[str,Characters[":,;.!? "]..];
Flatten@StringSplit[tmp,WordBoundary~~Apply[Alternatives,stopwords]~~WordBoundary,IgnoreCase->True]
]


FindSubsequence[num_?NumberQ,subseq_?NumberQ]:=Module[{n=ToString[num],s=ToString[subseq]},
StringPosition[Part[StringSplit[n,"."],2],s]
]


(* Alternative definition using SequencePosition *)
(* 
FindSubsequence[num:{__?NumberQ},subseq_?NumberQ]:=
SequencePosition[num,IntegerDigits[subseq]]
*)


FindWordsContaining[str_String,OptionsPattern[]]:=Module[{wp=OptionValue[WordPosition]},
Which[
wp=="Start",DictionaryLookup[RegularExpression[StringJoin["\\b",str,".*\\b"]]],
wp=="Middle",DictionaryLookup[RegularExpression[StringJoin["\\b.+",str,".+\\b"]]],
wp=="End",DictionaryLookup[RegularExpression[StringJoin["\\b.*",str,"\\b"]]],
wp=="Anywhere",DictionaryLookup[RegularExpression[StringJoin["\\b.*",str,".*\\b"]]]
]]


gcRatio[ls_String]:=Module[{gc},
gc=StringCount[ls,"G"|"C"];
N[gc/StringLength[ls]]
]


GCRatio[str_String,blocksize_Integer]:=Module[{lis,blocks},
lis=stringPartition[str,blocksize];
blocks=Table[i,{i,1,StringLength[str],blocksize}];
Transpose[{blocks,Map[gcRatio,lis]}]
]


GCRatio[{str_String},blocksize_Integer]:=GCRatio[str,blocksize]


MakeVarList[x_Symbol,n_Integer]:=ToExpression[Map[ToString[x]<>ToString[#]&,Range[n]]]


MakeVarList[x_Symbol,{n_Integer?Positive,m_Integer?Positive}]:=ToExpression[Map[ToString[x]<>ToString[#]&,Range[n,m]]]


If[$VersionNumber<10.3,
PalindromeQ[str_String]:=StringReverse[str]==str]


If[$VersionNumber>=10.3,
palindromeQ[str_String]:=StringReverse[str]==str]


If[$VersionNumber<10.3,
PalindromeQ[num_Integer]:=PalindromeQ[ToString[num]]]


If[$VersionNumber>=10.3,
palindromeQ[num_Integer]:=palindromeQ[ToString[num]]]


Palindromes[len_Integer]:=DictionaryLookup[w__/;(w==StringReverse[w] && StringLength[w]==len)]


Palindromes[]:=DictionaryLookup[w__/;(w==StringReverse[w] )]


RandomString[{c__String},n_Integer,OptionsPattern[]]:=Module[{wts=OptionValue[Weights]},
Which[
Length[wts]==0,StringJoin[RandomChoice[{c},n]],
Length[wts]==Length[{c}],StringJoin[RandomChoice[wts->{c},n]],
True,Message[RandomString::badwt]
]]


RandomString[{c__String},opts:OptionsPattern[]]:=RandomString[{c},1,opts]


RandomString[{c__String},{n_Integer,len_Integer},OptionsPattern[]]:=Module[{wts=OptionValue[Weights]},
Which[
Length[wts]==0,Map[StringJoin,RandomChoice[{c},{n,len}]],
Length[wts]==Length[{c}],Map[StringJoin,RandomChoice[wts->{c},{n,len}]],
True,Message[RandomString::badwt]
]]


SequenceTable[lis_String,opts:OptionsPattern[]]:=
Module[{n=OptionValue[BlockSize],len=StringLength[lis],r=OptionValue[RowLength],str,blocks,ind},
str=stringPartition[lis,n];
blocks=Partition[str,r,r,1," "];
ind=Select[Range[len],Mod[#,r*n]==1&];
Grid[MapThread[Prepend[#1,#2]&,{blocks,ind}],
FilterRules[{opts}, Options[Grid]],Alignment->{{Right,{Left}},Automatic},ItemStyle->{8},Frame->True,Dividers->{{True,False},All}]
]


StringPad[str_String,{n_}]:=StringJoin[str,Table[" ",{n}]]


StringPad[str_String,n_]:=With[{len=StringLength[str]},If[len>n,Message[StringPad::badlen,n,str],StringPad[str,{n-len}]]]


StringPad[str_String,n_,m_]:=StringJoin[Table[" ",{n}],str,Table[" ",{m}]]


stringPartition[str_String,seq__]:=Map[StringJoin,Partition[Characters[str],seq]]


stringPartition[str_String,blocksize_]:=Map[StringJoin,Partition[Characters[str],blocksize,blocksize,1,{}]]


StringPermutations[str_String]:=Map[StringJoin,Permutations[Characters[str]]]


StringTally[text_,OptionsPattern[]]:=Module[{ic=OptionValue[IncludeCharacters],igcase=OptionValue[IgnoreCase]},
Tally[StringCases[If[igcase,ToLowerCase[text],text],
Which[
ic===AllCharacters,RegularExpression["."],
ic===WordCharacters,RegularExpression["\\w"],
ic===PunctuationOnly,RegularExpression["\\W"],
True,Message[StringTally::badopt,ic]
]
]]]


StringTranspose[str1_String,str2_String]:=StringJoin[Transpose[{Characters[str1],Characters[str2]}]]


UcLc[word_String]:=StringReplace[word,RegularExpression["(.)([a-z]+)"]:>ToUpperCase["$1"]~~"$2"]


UniqueCharacters[str_String]:=DeleteDuplicates[Characters[str]]


XorEncode[text_String,key_String]:=Module[{lis,bitText,bitKey},
bitText=IntegerDigits[ToCharacterCode[text],2,8];bitKey=First@IntegerDigits[ToCharacterCode[key],2,8];
lis=Map[BitXor[#,bitKey]&,bitText];
FromCharacterCode[Map[FromDigits[#,2]&,lis]]
]


End[];


(*EndPackage[]*)



