Register Guidelines E-Books Today's Posts Search

Go Back   MobileRead Forums > E-Book Software > Sigil

Notices

Reply
 
Thread Tools Search this Thread
Old 01-12-2026, 01:20 PM   #16
theducks
Well trained by Cats
theducks ought to be getting tired of karma fortunes by now.theducks ought to be getting tired of karma fortunes by now.theducks ought to be getting tired of karma fortunes by now.theducks ought to be getting tired of karma fortunes by now.theducks ought to be getting tired of karma fortunes by now.theducks ought to be getting tired of karma fortunes by now.theducks ought to be getting tired of karma fortunes by now.theducks ought to be getting tired of karma fortunes by now.theducks ought to be getting tired of karma fortunes by now.theducks ought to be getting tired of karma fortunes by now.theducks ought to be getting tired of karma fortunes by now.
 
theducks's Avatar
 
Posts: 31,417
Karma: 62503914
Join Date: Aug 2009
Location: The Central Coast of California
Device: Kobo Libra2,Kobo Aura2v1, K4NT(Fixed: New Bat.), Galaxy Tab A
My standard for those cases is to first Lower, then do the desired case.
theducks is offline   Reply With Quote
Old 01-12-2026, 01:38 PM   #17
jwes
Connoisseur
jwes began at the beginning.
 
Posts: 96
Karma: 10
Join Date: Jul 2023
Device: none
Quote:
Originally Posted by KevinH View Post
There is no universal titlecase function that works on every string in every language as even in English the rules for what gets titlecased are not generally agreed upon under certain styles or grammar rules. And yes if something is in all caps, title case generally ignores it as allcaps indicates it may be an abbreviation, or acronyms.

If you want to handle all caps cases then in your own python function replace do two things with the first lowercasing the string, and the second titlecases it. But be careful for acronyms.
Perhaps I did not explain myself clearly. It works the way I would expect for strings that contain no lowercase characters and it works for strings that have words with only initial capital or no capital letters. It does not work the way I would expect for strings that have words that are all capitalized and other words that have lower case letters.

If you change the line in titlecase.py about line 61
Code:
from:
        if all_caps:
to
        if toUpper(word) == word:
then it appears to work the way I would expect.
jwes is offline   Reply With Quote
Old 01-12-2026, 02:21 PM   #18
KevinH
Sigil Developer
KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.
 
Posts: 9,234
Karma: 6565382
Join Date: Nov 2009
Device: many
Quote:
Originally Posted by jwes View Post
Perhaps I did not explain myself clearly. It works the way I would expect for strings that contain no lowercase characters and it works for strings that have words with only initial capital or no capital letters. It does not work the way I would expect for strings that have words that are all capitalized and other words that have lower case letters.

If you change the line in titlecase.py about line 61
Code:
from:
        if all_caps:
to
        if toUpper(word) == word:
then it appears to work the way I would expect.

Not sure I follow, unless I am missing something if I make that change, how will it ignore titles already in all Uppercase?

If a title string is all uppercase, then each word of the title is all uppercased and the same thing happens as UC_INITIALS regex should return true for all words in a string that is all capitalized.

How all caps is handled is by design in the titlecase routine.

If you don't want that, then in your own replace function forcibly lowercase any strings you want to force to titlecase first. You can do that right in your own titlecase function. That is the power of python function replace.

Simply use the replace_lowercase call and store its result then assign it to the match.string in the match object passed in and then invoke the replace_titlecase.

If the titlecase.py code did not ignore things already in all caps, then it would make it hard to ignore titles already in all uppercase for a reason (ie. higher level major section titles often use all uppercase). You can control how that gets handled in your own function.

Last edited by KevinH; 01-12-2026 at 03:07 PM.
KevinH is offline   Reply With Quote
Old 01-12-2026, 03:03 PM   #19
KevinH
Sigil Developer
KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.
 
Posts: 9,234
Karma: 6565382
Join Date: Nov 2009
Device: many
In case this helps. Here is a python function replacement to force titlecase even when the entire string is all caps.

Code:
def replace(match, number, file_name, metadata, data):
    if match:
        new_match = match
        new_match.string = replace_lowercase(match, number, file_name, metadata, data)
        return replace_titlecase(new_match, number, file_name, metadata, data)
And so I used the Python Function Replace editor to create a new replacement function I called "force_titlecase"

And then my replace string becomes:

\F<force_titlecase>

If you edit this be careful not to introduce tabs in place of spaces as this is entirely indented in groups of 4 spaces.

Hope this helps.

With this replacement function even the string "DOWN THE RABBIT-HOLE" which should be skipped by normal titlecase calls will be coverted to "Down the Rabbit-Hole".

Last edited by KevinH; 01-12-2026 at 03:06 PM.
KevinH is offline   Reply With Quote
Old 01-12-2026, 05:15 PM   #20
jwes
Connoisseur
jwes began at the beginning.
 
Posts: 96
Karma: 10
Join Date: Jul 2023
Device: none
Quote:
Originally Posted by KevinH View Post
In case this helps. Here is a python function replacement to force titlecase even when the entire string is all caps.

Code:
def replace(match, number, file_name, metadata, data):
    if match:
        new_match = match
        new_match.string = replace_lowercase(match, number, file_name, metadata, data)
        return replace_titlecase(new_match, number, file_name, metadata, data)
And so I used the Python Function Replace editor to create a new replacement function I called "force_titlecase"

And then my replace string becomes:

\F<force_titlecase>

If you edit this be careful not to introduce tabs in place of spaces as this is entirely indented in groups of 4 spaces.

Hope this helps.

With this replacement function even the string "DOWN THE RABBIT-HOLE" which should be skipped by normal titlecase calls will be coverted to "Down the Rabbit-Hole".
I believe the code doesn't do exactly what you think it does.
These are the results I get with the current version.

titlecase of 'DOWN THE RABBIT-HOLE' is 'Down the Rabbit-Hole
titlecase of 'DOWN the RABBIT-HOLE' is 'DOWN the RABBIT-HOLE
titlecase of 'down the rabbit-hole' is 'Down the Rabbit-Hole
titlecase of 'Down The Rabbit-Hole' is 'Down the Rabbit-Hole
titlecase of 'Down the rabbit-hole' is 'Down the Rabbit-Hole
titlecase of 'DOWn tHe rabbIT-HOLE' is 'DOWn tHe rabbIT-HOLE

These are the results I get with my change.

titlecase of 'DOWN THE RABBIT-HOLE' is 'Down the Rabbit-Hole
titlecase of 'DOWN the RABBIT-HOLE' is 'Down the Rabbit-Hole
titlecase of 'down the rabbit-hole' is 'Down the Rabbit-Hole
titlecase of 'Down The Rabbit-Hole' is 'Down the Rabbit-Hole
titlecase of 'Down the rabbit-hole' is 'Down the Rabbit-Hole
titlecase of 'DOWn tHe rabbIT-HOLE' is 'DOWn tHe rabbIT-HOLE
jwes is offline   Reply With Quote
Old 01-12-2026, 05:46 PM   #21
KevinH
Sigil Developer
KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.
 
Posts: 9,234
Karma: 6565382
Join Date: Nov 2009
Device: many
No. You must have either not created the force_titlecase function properly or ran my force_titlecase function with your modified titlecase.py.

Notice the call to replace_titlecase in the force_titlecase uses new_match which was created by lowercasing everything first.

With stock titlecase.py for all of your testcases with my force_titlecase function, all of them convert to "Down the Rabbit-Hole" as expected. I just double-checked that.

Since they are lowercased first then all_caps must be false and no exceptions are handled. In your modified version it still will leave individual words that are ALL caps alone. That is not forcing titlecase.

That is why that titlecase.py stock, is correct as it was. It properly handles the case of the entire title being in all caps, which should be left alone. Your change invalidates that.

Please retry with the exact force_titlecase python function replace (copy and pasted from earlier to prevent errors) and stock titlecase.py (before any of your changes).

I did just that and all your test cases work.

Last edited by KevinH; 01-12-2026 at 06:59 PM.
KevinH is offline   Reply With Quote
Old 01-12-2026, 09:46 PM   #22
jwes
Connoisseur
jwes began at the beginning.
 
Posts: 96
Karma: 10
Join Date: Jul 2023
Device: none
Quote:
Originally Posted by KevinH View Post
No. You must have either not created the force_titlecase function properly or ran my force_titlecase function with your modified titlecase.py.

Notice the call to replace_titlecase in the force_titlecase uses new_match which was created by lowercasing everything first.

With stock titlecase.py for all of your testcases with my force_titlecase function, all of them convert to "Down the Rabbit-Hole" as expected. I just double-checked that.

Since they are lowercased first then all_caps must be false and no exceptions are handled. In your modified version it still will leave individual words that are ALL caps alone. That is not forcing titlecase.

That is why that titlecase.py stock, is correct as it was. It properly handles the case of the entire title being in all caps, which should be left alone. Your change invalidates that.

Please retry with the exact force_titlecase python function replace (copy and pasted from earlier to prevent errors) and stock titlecase.py (before any of your changes).

I did just that and all your test cases work.
The results I posted are with the stock titlecase function. The stock titlecase function does not preserve strings that are all caps, but it does preserve words that are all caps if there are any lower case letters in the string. If you look at the code from titlecase.py, you can see that if the string has no lowercase characters then it sets each word to lowercase unless UC_INITIALS.match(word) is true and then applies the titlecase algorithm to them.

A snippet of code from line 61 of titlecase.py
Code:
        if all_caps:
            if UC_INITIALS.match(word):
                line.append(word)
                continue
            else:
                word = toLower(word)
jwes is offline   Reply With Quote
Old 01-12-2026, 10:58 PM   #23
KevinH
Sigil Developer
KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.
 
Posts: 9,234
Karma: 6565382
Join Date: Nov 2009
Device: many
Again, something is different as all of my tests show the new force_titlecase replace function works as I posted it, against all your tests on both macOS and linux machines I have to test with.

Please show a screencap of the python function editor showing your version of the force_titlecase function, and a screencap showing it being used in Sigil's find and replace.

If they are identical then something is broken somewhere in your setup. The replace_titlecase does work with all lowercase strings and we are making them lowercase in the force_titlecase replace function I posted by invoking replace_lowercase first.

Maybe some indentations in the python code got changed someplace?

It is very strange you are not seeing what I am seeing when adding and using the force_titlecase replacement function.

Something is different but I do not know what. The unchanged titlecase.py function does work when given mixed case or all lowercase test. We proved that earlier.

Last edited by KevinH; 01-12-2026 at 11:27 PM.
KevinH is offline   Reply With Quote
Old 01-12-2026, 11:02 PM   #24
KevinH
Sigil Developer
KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.
 
Posts: 9,234
Karma: 6565382
Join Date: Nov 2009
Device: many
FWIW: all_caps will *always* be false in the new forced_titlecase code all the time so that entire block is not used when the new force_titlecase python replacement function is used.

I have attached a screenshot with your testcases set up in the xhtml, and a screenshot of the new force_titlecase function inside the Python Function Editor (just hit the cursive f 'for function' in the Find Replace dialog to access the Python Function Editor). And finally the results from hitting find followed by replace for each test case.

As you can see it works perfectly.

I have also attached a public domain junk_test.epub that has your test cases in chapter 1, in case you want to use it in your testing.

As an aside, when allcaps is true, a single word in all uppercase will always match the UC_INITIALS regex. It will not match mixed case, meaning it will pass it through unchanged.
Attached Thumbnails
Click image for larger version

Name:	your_testcase_before.png
Views:	12
Size:	286.5 KB
ID:	220269   Click image for larger version

Name:	python_function_editor.png
Views:	11
Size:	89.0 KB
ID:	220270   Click image for larger version

Name:	results_forced_titlecase.png
Views:	12
Size:	287.3 KB
ID:	220271  
Attached Files
File Type: epub junk_test.epub (5.93 MB, 4 views)

Last edited by KevinH; 01-12-2026 at 11:29 PM.
KevinH is offline   Reply With Quote
Old 01-12-2026, 11:43 PM   #25
KevinH
Sigil Developer
KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.
 
Posts: 9,234
Karma: 6565382
Join Date: Nov 2009
Device: many
And I repeated that test under Manjaro Linux with a fresh build from master just now (which has the functionsearch.py fix we used earlier in this thread) with the junk_test.epub, and the code copy and pasted from from my earlier post to create the force_titlecase replacement function.

All your test cases now work.

You should be seeing the exact same thing. If not, then we really need to figure how the code we are using differs!
KevinH is offline   Reply With Quote
Old 01-13-2026, 12:06 AM   #26
DNSB
Bibliophagist
DNSB ought to be getting tired of karma fortunes by now.DNSB ought to be getting tired of karma fortunes by now.DNSB ought to be getting tired of karma fortunes by now.DNSB ought to be getting tired of karma fortunes by now.DNSB ought to be getting tired of karma fortunes by now.DNSB ought to be getting tired of karma fortunes by now.DNSB ought to be getting tired of karma fortunes by now.DNSB ought to be getting tired of karma fortunes by now.DNSB ought to be getting tired of karma fortunes by now.DNSB ought to be getting tired of karma fortunes by now.DNSB ought to be getting tired of karma fortunes by now.
 
DNSB's Avatar
 
Posts: 49,564
Karma: 174632684
Join Date: Jul 2010
Location: Vancouver
Device: Kobo Sage, Libra Colour, Lenovo M8 FHD, Paperwhite 4, Tolino epos
For what it may be worth, under Windows 11 and SUSE Tumbleweed, my results looked the same as in the images posted in message #24.
DNSB is offline   Reply With Quote
Old 01-13-2026, 11:06 AM   #27
KevinH
Sigil Developer
KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.KevinH ought to be getting tired of karma fortunes by now.
 
Posts: 9,234
Karma: 6565382
Join Date: Nov 2009
Device: many
Quote:
Originally Posted by DNSB View Post
For what it may be worth, under Windows 11 and SUSE Tumbleweed, my results looked the same as in the images posted in message #24.
Whew! I thought I was going crazy. Thank you for confirming it works for you as expected on Windows 11 and your Linux box.

That confirms it works for all platforms. Now, we just need to figure out what is making it act differently for @jwes.
KevinH is offline   Reply With Quote
Reply


Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Volunteer to write new Chapter on Python Function Replace for Sigil User Guide KevinH Sigil 8 06-03-2025 08:11 PM
Python function terminated unexpectedly woodr2011 Library Management 12 11-04-2019 06:26 PM
Python function terminated stmbtbob Devices 2 05-08-2015 09:21 AM
Python Function Error LoveMissBubbly Calibre 5 09-21-2011 05:52 PM
txt2html function in python benluo Calibre 0 11-15-2010 10:27 AM


All times are GMT -4. The time now is 08:34 AM.


MobileRead.com is a privately owned, operated and funded community.