Page 1 of 1

Updating Footnoted Text

Posted: Mon Nov 27, 2017 9:24 pm
by montymay
Hello Dear Reader

I am seeking a pointer or a little guidance on the code for updating a text field that has footnotes as numbered links. For example:
Hitchhiker's Guide to the Universe was written by Douglas Adams.FN1 Towel Day is celebrated on May 25 in Innsbruck, Austria.FN2
Using read from file, the field is populated by an external text file, the footnotes text having been tagged with html. I want a user to be able to edit this example by adding a new statement supported by a footnote, such as writing a sentence between the first and second sentence. Thus, in the example, the footnote number of the new sentence would become FN2, and the footnote for the last sentence would become FN3.
Hitchhiker's Guide to the Universe was written by Douglas Adams.FN1 He was born in England and died in California.FN2 Towel Day is celebrated on May 25 in Innsbruck, Austria.FN3
I am not a trained programmer, so that only method I can think is the following. The user types the second sentence, adds the following marked footnote text after its period, and presses a button. <Born 1952; Died in 2001> Thus:
Hitchhiker's Guide to the Universe was written by Douglas Adams.FN1 He was born in England and died in California.<Born 1952; Died 2001.> Towel Day is celebrated on May 25 in Innsbruck, Austria.FN2
Here is just the beginning of the procedure. The function seems to get the correct footnote number, but after many experiments I still cannot figure out the code to insert "FN2" after "California." in the text file "Adams.txt":

Code: Select all

  
  put offset("<", fld("text")) into tCharPos1
  put offset(">", fld("text")) into tCharPos2
  
  --get the footnote 
  put char tCharPos1 to tCharPos2 of fld "text" into tFootnote
  --get the text preceding the footnote
  put char 1 to (tCharPos1-1) of fld "text" into tFieldText
  --query: now, how should tFieldText be parsed so that the code below will capture the 
  same text in the file "Adams.txt"?
   
 open file "Adams.txt" for update
 read from file "Adams.txt" until ? | for ?

## If the variable "it" contains the the text preceding the footnote, 
## this code seems to work:
   
   put NumOccurrInText("<a>", it) into tNumOccurr
   Add 1 to tNumOccurr
   write "<a>FN"&tNumOccurr&"</a>" to file "Adams.txt" at ? | start ?
   close "Adams.txt"
     
  function NumOccurrInText pSearch, pCont
  put 0 into rNumOccurrInText
  put 0 into tCharsToSkip
   repeat
      put offset(pSearch, pCont, tCharsToSkip) into OneOccurr
      if OneOccurr = 0 then exit repeat
      add OneOccurr to tCharsToSkip
      add 1 to rNumOccurrInText
   end repeat
   return rNumOccurrInText
 end NumOccurrInText
My apologiies for the long post. Hope some patient programmer immediately sees the solution. I don't necessarily want someone to write the correct code, but perhaps a pointer could be the catalyst for my discovery of the solution.

Monty May

Re: Updating Footnoted Text

Posted: Mon Nov 27, 2017 11:35 pm
by dunbarx
Hitchhiker's Guide to the Universe was written by Douglas Adams.
The "answer" in this case must be different than "42".

Craig

Re: Updating Footnoted Text

Posted: Wed Dec 06, 2017 8:01 am
by montymay
Hello Dunbarx and others

Just a followup to my request for help. The meaning of the only reply so far has eluded me. As I said, I don't want anyone to write the code, just hoping that an experienced programmer could share a little pointer or clue to the algorithm that could be used. The function seems to work, but I have yet to find the code for writing a new sentence and its <footnote> to the external text file, while preserving the text that follows the footnote. Here's my latest amateurish effort.

Code: Select all

global gComputer
on mouseup
## get the footnote
   put offset("<", fld("text")) into tCharPos1
   put offset(">", fld("text")) into tCharPos2
   put char tCharPos1 to tCharPos2 of fld "text" into tFootnote
   delete the first char of tFootnote
   delete the last char of tFootnote

   
   ## get the body text before the occurrence of marked footnote
   put char 1 to (tCharPos1-1) of fld "text" into tOldText_NewText
   
   ## get the new text
   put the last sentence of tOldText_NewText into tNewText
   ## get the old text
   put sentence 1 to -2 of tOldText_NewText into tOldText
   ## get the last word of the old text
   put the last word of tOldText into tLastOldWord
   ## open the text file and update it  
   open file tFolder&tTitle&".txt" for update
   read from file tFolder&tTitle&".txt" until tLastOldWord
    put NumOccurrInText("<a>", it) into tNumOccurr
   Add 1 to tNumOccurr
   put it & tNewText & "<a>FN"&tNumOccurr&"</a>" into tUpdatedText
   write tUpdatedText to file tFolder&tTitle&".txt" at 0
   close file tFolder&tTitle&".txt"

   function NumOccurrInText pSearch, pCont
   put 0 into rNumOccurrInText
   put 0 into tCharsToSkip
   repeat
      put offset(pSearch, pCont, tCharsToSkip) into OneOccurr
      if OneOccurr = 0 then exit repeat
      add OneOccurr to tCharsToSkip
      add 1 to rNumOccurrInText
   end repeat
   return rNumOccurrInText
end NumOccurrInText
The problem with this code is that the text following the new footnote is overwritten. The number of overwritten characters seems to equal the number of characters in the variable tUpdatedText.

Here's hoping

Monty

Re: Updating Footnoted Text

Posted: Wed Dec 06, 2017 3:55 pm
by bogs
montymay wrote:
Wed Dec 06, 2017 8:01 am
The meaning of the only reply so far has eluded me.
Craig was using your example for an insider (to the hitchhiker's guide) joke.
Image
(click the pic to go to Wikipedia entry)

Re-looking at your code and information in the second post, will see if I can find anything blatantly obvious.
*Edit - missing 'end mouseUp' in code.
*Edit - as a general rule, I wouldn't use reserved words for object names, i.e. [ fld "text" ].
*Edit - as another general rule, I wouldn't rely on "it" for information, if you want something stored, use a variable because "it" is pretty unreliable (well, not unreliable, "it" always stores 'something', but that something is subject to change without your realization -
Image
*Edit - sentence is meaningless to Lc - perhaps you mean 'line' ? Corrected, see Craig's post below...

Code: Select all

## get the new text
   // put the last sentence of tOldText_NewText into tNewText - throws error
## get the old text
   // put sentence 1 to -2 of tOldText_NewText into tOldText - error

Re: Updating Footnoted Text

Posted: Wed Dec 06, 2017 8:00 pm
by dunbarx
The "Hitchhiker's Guide to the Galaxy" must be a prequel to the "Hitchhiker's Guide to the Universe".

But "sentence" is indeed a new chunk expression in LC. I feel so much more powerful, now, because just a month ago I would not have known about it, languishing in v.6.7.

Anyway, Bogs will track down your problems.

Craig

Re: Updating Footnoted Text

Posted: Wed Dec 06, 2017 8:20 pm
by bogs
dunbarx wrote:
Wed Dec 06, 2017 8:00 pm
But "sentence" is indeed a new chunk expression in LC. I feel so much more powerful, now, because just a month ago I would not have known about it, languishing in v.6.7.
Well, maybe I will, as you know I am happily doing my coding many many generations back :D I would never have guessed about "sentence", because the few times I have adventures in anything later than 6.x, I use the language features I know (from 6.x back).

I will look at it more tonight if I get time, tomorrow at the latest.

Re: Updating Footnoted Text

Posted: Wed Dec 06, 2017 8:34 pm
by jacque
I think I'd do something like this: First, every footnote must use a distinguishing string, like the "FN" in your example. That will be the search string for renumbering. Then:

Get the sentenceOffset() of the new entry.
Subtract 1 from that and parse out the footnote number of the previous sentence. (If that sentence doesn't have a footnote, you'll have to keep going backwards until you find one that does.) Initialize a counting variable with that number.
Start a sentenceOffset() repeat loop, starting with the offset of the new footnote, looking for each footnote entry and setting its number to the next increment. For example, if the sentence before the new insertion is FN2, then initialize the count with 3 and update the text of the new entry with "FN3" and increase each subsequent footnote by one. You'll want to use the third "skip" parameter to search serially through all the text, which is very fast.

The basic idea is to find the last valid footnote number, and then renumber all the footnotes after that one.

Re: Updating Footnoted Text

Posted: Thu Dec 07, 2017 4:59 pm
by bogs
Jacque's reply makes the most sense.

Other than what I pointed out, I didn't see any obvious flaws, however if you put a break point in the debugger at the beginning of your code and step through it, you will see that most of the variables don't contain the values I think you think they should.

Re: Updating Footnoted Text

Posted: Fri Dec 08, 2017 7:51 pm
by montymay
Thank you Jacque for your note. Sorry to be a bother, buI I used sentenceOffset and right away I found a problem in using the sentence chunk: any period punctuation mark will be treated as the end of a sentence, e.g., the initials of a name, such as "Sons and Lovers was written by D. H. Lawrence." The dictionary entry says
a sentence is a chunk delimited by Unicode sentence breaks, as determined in the ICU Library. . . . The rules describing Unicode sentence breaks are available at . . . "
and a link is given to an entry on the Unicode.org. The information given there is too technical for me. Do you think there may be a way to force a Unicode sentence break when a user enters a sentence such as the above, or is the use of the sentence chunk for my purposes not an option, leaving wordoffset or something other chunk as the method?

Monty

Re: Updating Footnoted Text

Posted: Fri Dec 08, 2017 9:21 pm
by dunbarx
You may have to roll your own chunk delimiter, using offset (perhaps more than once) in its other forms.

Or,

Might you temporarily:

Code: Select all

replace "." with numToChar(166) in yourText
Then do your sentenceOffset, and then restore the periods? Or something like that, I do not know if that is as straightforward as it seems. But something will work. It always does...

Craig

Re: Updating Footnoted Text

Posted: Fri Dec 08, 2017 9:50 pm
by jacque
Replacing all periods would remove most of the sentence markers, so that won't work. The problem is a little tricky due to the unstructured format of the text. The basic idea is the same as I mentioned before: identify the preceding footnote and renumber all subsequent ones. The problem is in the identification. An entry may contain more than one sentence, or possibly a single sentence may contain more than one footnote.

The key is still to have an identifying string in each footnote ("FN" for example). That gives a marker you can search for. I can think of a couple of ways to proceed:

1. Discontinue using sentenceOffset() and instead use plain offset(). Loop through the text searching for footnotes by character offset rather than sentences: get offset(tText,"FN",tSkip). Since offset() can't go backwards, you need to save the character position of the new entry, loop through the text until it exceeds that position, and then start adding and/or updating subsequent footnotes. As the loop proceeds, keep a temporary list of offset values and footnote numbers so you can find the one previous to the new entry offset and start numbering from there.

2. Another option might be to set the itemDelimiter to "FN" and loop through the "items" of the text with a normal "repeat for each" loop. Check the content of each item to see if it includes the new entry. If so, add a footnote number to that and then update all the following footnotes. Now that I think about it, this might be easier than messing around with offset().

Option #2 might do well as a numerically-keyed array. You'd have to experiment. An array would provide automatic numbering.

Both techniques require that you identify the new entry text and position so you can spot it later. I'm not sure of the best way to do that; you might compare the original text with the new text in the field and parse out the differences on closeField. I'd have to think about that. Maybe I'll mess around with it over the weekend if no one else comes up with something.

Re: Updating Footnoted Text

Posted: Fri Dec 08, 2017 10:20 pm
by jacque
Never mind, I was making it too hard. All you need is a conversion to an array:

Code: Select all

on updateFN -- update footnote numbers
  put fld 1 into tText
  split tText by "FN"
  get item 2 of the extents of tText
  repeat with k = 1 to it
    put tText[k] into tData
    if word 1 of tData is an integer then delete word 1 of tData
    if tData = "" then next repeat
    put tData & "NF" & k & space after tUpdate
  end repeat
  -- put tUpdate into a field or whatever
end updateFN
This assumes "FN" as the delimiter, use whatever you want as long as it's consistent.

Edit: this doesn't preserve paragraphs. It needs some tinkering.

Re: Updating Footnoted Text

Posted: Mon Dec 11, 2017 7:15 pm
by TerryL
Hi MontyMay. I came up with a solution using wordOffset(). Turns out not so easy. There must be a space after the sentence's period to make the placeholder "FN" a word. Existing text formatting is preserved using the htmlText property. There's an option for renumbering a footnote list at the end of the text using the placeholder "FOOTNOTES" on one line.

The tricky part was recognizing the difference between an unformatted and formatted footnote by user-menu or code. The textShift property can't be set in a container but the tag for it can. The result though is a two-word footnote: <sup shift="-4">FN2</sup>. This requires some slight-of-hand and hand-to-aching-head to format & update a one-word unformatted FN and only update a two-word formatted FN while keeping the skip# straight. Terry

Footnote.png
Footnote.png (3.18 KiB) Viewed 6344 times

Code: Select all

on mouseUp  --update footnote numbering   (use word "FN" placeholder for footnote#)
   local tText, tSkip = "0", tCount = "1", tStart, tEnd
   if fld "A" = empty then
      answer "Sorry, there's nothing to update." with "OK" titled "Error"
      exit to top
   end if
   put the htmlText of fld "A" into tText  --preserve formatting
   set the caseSensitive to "true"  --uppercase "FN" only
   --setting the textShift property via user-menu or code to superscript (-4) creates a two-word tag.
   --format & update one-word unformatted FN or update two-word formatted FN:
   repeat forever
      if ctrlKey() = "down" then exit to top  --failsafe
      get wordOffset("FN",tText,tSkip)  --word
      if it = "0" then exit repeat  --not found/finished
      add it to tSkip  --continue search
      if "</sup>" is not in word tSkip of tText then  --format & update one-word FN
         put "<sup shift=" &quote&"-4"&quote& ">FN" &tCount& "</sup>" into word tSkip of tText
         add 1 to tSkip  --now two words
      else put "<sup shift=" &quote&"-4"&quote& ">FN" &tCount& "</sup>" into word (tSkip-1) to tSkip of tText  --update two-word FN
      add 1 to tCount
   end repeat
   get lineOffset("FOOTNOTES",tText)
   if it <> "0" then  --update numbered FOOTNOTES list   (use ")" placeholder for footnote#/line)
      put (it+1) into tStart
      put number(lines in tText) into tEnd
      put "1" into tCount
      repeat with i = tStart to tEnd
         if line i of tText = empty then next repeat
         if ")" is in word 1 of line i of tText then put tCount &")" into word 1 of line i of tText  --sequence
         add 1 to tCount
      end repeat
   end if
   set the htmlText of fld "A" to tText  --restore formatting
end mouseUp