Searches plain-text database of TCM herbal formulas and displays the matches, formulas with more matches are displayed first. Written in Julia ("julialang").


Each entry is in the format: first line is 5 = signs; title; ingredients; empty line; indications. eg:

=====
beijing city government coronavirus formula for kids with high fever
ma huang, sheng shi gao, zhi mu, xing ren, sheng yi yi ren, quan gua lou, shu da huang, sang bai pi, ting li zi, shui niu jiao, di long, ren shen 

high fever, cough, restlessness, yellow phlegms, maybe constipation, dry throat with thirst, red tongue, yellow tongue coating, floating and slippery pulses, purple fingerprints.

DISCLAIMER: Do not self-prescribe or prescribe for others. To be effective, a qualified practitioner will adjust the formula to suit the patient condition.


  


#!/usr/bin/env julia

using Dates, StatsBase

line = 0::Int
formulaNumber = 0::Int
formulaLine = 0::Int
searchResult = ""::String
searchArray = ""::String                                                               
searchLength = 0::Int

#   columns in array:   1=name, 2=herbs in formula, 3=formula notes (altered), 
#               4=search result score, 5=formula notes (unaltered).
formulaArray = Array{Union{Nothing, Any}}(nothing, 1000, 5)

run(`clear`)
println("\n\n\t\tScanning...")

# Initialise 4th column elements as zeros (can then be used for the score for each formula):
function allZeros()
  for x in 3001:4000
    formulaArray[x] = 0
  end
end

open("/home/brett/aa___my-notes/A--Herbs---Formulas/a------MY-FORMULA-LIST.txt") do io
  while ! eof(io)
      textLine::String = readline(io)
      global line += 1
      if textLine == "====="
          global formulaLine = 0
      global formulaNumber += 1
    else
          formulaLine += 1
      # Record formula name:
          if formulaLine == 1
        formulaArray[formulaNumber] = "$textLine"
      # Record formula ingredients:
      elseif formulaLine == 2
        formulaArray[formulaNumber + 1000] = "$textLine"
      else
        # If element contains nothing, record formula notes:
        if formulaArray[formulaNumber + 4000] === nothing
          formulaArray[formulaNumber + 4000] = "$textLine"
        # If element already contains notes, apend any further notes:
        else
          tempContents = formulaArray[formulaNumber + 4000] * "\n" * "$textLine"
          formulaArray[formulaNumber + 4000] = tempContents::String
        end
          end
      end
  end
end

run(`clear`)
println("\n\n\t\t\t Formulas scanned: ", formulaNumber)

function getSearchTerms()
  # Reset scores:
  allZeros()
    # Clear search results from any previous searches:
    global searchResult = " "
  # Copy unaltered notes into 2001:3000 from 4001:5000:
  for N in 2001:3000
    global formulaArray[N] = formulaArray[N + 2000] 
  end
  print("\n\n  Enter search terms (comma separated), or x to exit:  ") 
  global searchTerms = readline()
  if searchTerms == "x"; run(`clear`); exit(); end
  global searchArray = split(searchTerms, ", ")
  global searchLength = length(searchArray)
  displaySearchTerms()
  scoreFormulas()
  recordResults()
  printResults()
  getSearchTerms()
end

# Display search terms on-screen:
function displaySearchTerms()
  println("\n  Search terms: \n")
  for term in 1:searchLength
    println("    ||  ", searchArray[term], "   ")
  end
end

# Look for search term in formula notes (3rd column), increment 4th column by 1 if it matches:
function scoreFormulas()
  for element in 1:searchLength
    for i in 2001:3000
      if formulaArray[i] != nothing
        if occursin(searchArray[element], formulaArray[i])
          # Increment score when match is found:
          formulaArray[i + 1000] += 1
          # Assign search term to variable A, element being search by variable B:
          A = searchArray[element]
          B = formulaArray[i]
          # Use `replace` to highlight any search terms found in 3rd column
          C = replace("$B", "$A" => "____[_`$A`_]____")
          # Put replaced text into original array:
          formulaArray[i] = C
        end
      end
    end
  end
end

# Record in searchResult all formulas matching search term(s), in order of highest to lowest:
function recordResults()
  maxScore::Int = maximum(formulaArray[3001:4000])
  for score in 1:maxScore
    # Using reverse score so highest scored are listed first:
    reverseScore::Int = maxScore - score + 1
    # Count how many times we got that score:
    E = countmap(formulaArray[3001:4000])
    occurances::Int = E[reverseScore]
    # Split over 2 lines:
    (global searchResult = searchResult * "\n******\n" * "Score: " * 
    string(reverseScore) * "\t\t Occurances: " * string(occurances) * "\n******\n\n\n\n")
    # add matching formula notes to searchResult (to be written to file):
    for y in 3001:4000
        if formulaArray[y] == reverseScore
        # Split over 2 lines:
            (global searchResult = searchResult * formulaArray[y - 3000] * "\n" * 
        formulaArray[y - 2000] * "\n" * formulaArray[y - 1000] * "\n======\n")
        end
    end
  end
end

function printResults()
  timeNow = Dates.format(now(), "eddu-HH:MM:SS")
  open("/tmp/formula$timeNow.txt", "w") do f
      write(f, "$searchResult\n")
    println(" ")
  end
  # open the file with leafpad:
  @async run(`leafpad /tmp/formula$timeNow.txt`)
  # open the file with micro on termux/android, instead of leafpad (and can't use @async):
  #run(`micro -softwrap true -wordwrap true -statusline false -scrollspeed 1 -readonly true -ruler false /tmp/formula$ timeNow.txt`)
  println(" ")
end

getSearchTerms()