Even more true title case Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
User avatar
menteith
Posts: 51
Joined: 04 Feb 2016, 12:22

Even more true title case

15 Jun 2016, 12:30

Hi all,

There have been a few attempts, here at AHK, to solve the problem of changing the case of a sentence to true title case, i.e. especially prepositions should written using lowercase. To my best knowledge, however, no solution has dealt with prepositions that start a sentence and end it. They should all be upper case.
Let's take the following sentence as an example.

The quick brown fox jumps over the lazy dog

This should be changed to:

The Quick Brown Fox Jumps over the Lazy Dog.
Over and the has not been written in upper case.

Let's consider the following nonsense sentence:

The quick brown fox jumps. over the lazy dog

This should be look this way:

The Quick Brown Fox Jumps. Over the Lazy Dog.

Over is in upper-case because it starts a new sentence.

A sentence can start with a dot and a space (. ), a question mark and a space (? ), an exclamation mark and a space (? ) and quite often a colon and a space (: ).
Quite often : goes after ? and ! i.e. ?: and !:

And the last thing: when a preposition ends a sentence it should be also in upper case.

Let consider the following two nonsense sentence:

The quick brown fox jumps at. over the lazy dog
-> The Quick Brown Fox Jumps At: Over the lazy dog

and another:

The quick brown lazy dog at
-> The Quick Brown Lazy Dog At

Here's my very simple attempt. I tried to list all the possibilities for "A" : ". A ", "? A " "! A " ": A " "?!: " etc.

Code: Select all

; based on: autohotkey.com/board/topic/56112-converting-to-proper-title-case/?p=352408
exclusions = |: A |?: A |. A |. An |. The | a | about| above| across| after | against| among| and | and,| around| as | as,| at | before|
Loop, parse, Clipboard, |
	{
	if A_LoopField not in %exclusions%
	StringUpper, Clipboard, A_LoopField, T
	else
	oVar := A_LoopField
	list .=  oVar " "  
	oList .= A_LoopField " "
	}
A short list of exclusions:
exclusions = a,an,and,as,at,between,but,by,for,if,in,of,on,or,the,to,with

Thanks for your help!


EDIT: Here's a code used to deal with this problem in Word using VBA

Code: Select all

Sub TrueTitleCase()
Dim sText As Range
Dim vFindText As Variant
Dim vReplText As Variant
Dim i As Long
Dim k As Long
Dim m As Long
Set sText = selection.Range
'count the characters in the selected string
k = Len(sText)
If k < 1 Then
'If none, then no string is selected
'so warn the user
MsgBox "Select the text first!", vbOKOnly, "No text selected"
Exit Sub 'and quit the macro
End If
'format the selected string as title case
sText.Case = wdTitleWord
'list the exceptions to look for in an array
vFindText = Array("A", "An", "And", "As", "At", "Between", "But", "By", "For", _
"If", "In", "Of", "On", "Or", "The", "To", "With")
'list their replacements in a matching array
vReplText = Array("a", "an", "and", "as", "at", "between", "but", "by", "for", _
"if", "in", "of", "on", "or", "the", "to", "with")
With sText
With .Find
'replace items in the first list
'with the corresponding items from the second
.ClearFormatting
.Replacement.ClearFormatting
.Forward = True
.Wrap = wdFindStop
.MatchWholeWord = True
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Format = True
.MatchCase = True
For i = LBound(vFindText) To UBound(vFindText)
.Text = vFindText(i)
.Replacement.Text = vReplText(i)
.Execute Replace:=wdReplaceAll
Next i
End With
'Reduce the range of the selected text
'to encompass only the first character
.MoveEnd Unit:=wdCharacter, Count:=-Len(sText) + 1
'format that character as upper case
.Case = wdUpperCase
'restore the selected text to its original length
.MoveEnd Unit:=wdCharacter, Count:=k
'and check to see if the string contains a colon
If InStr(1, sText, ":") > 0 Then
'If it does note the position of the character
'after the first colon
m = InStr(1, sText, ":") + 1
'and set that as the new start of the selected text
.MoveStart wdCharacter, m
'set the end of the selected text to include
'one extra character
.MoveEnd Unit:=wdCharacter, Count:=-Len(sText) + 1
'format that character as upper case
.Case = wdUpperCase
End If
End With
End Sub
Last edited by menteith on 17 Jun 2016, 08:59, edited 1 time in total.
An ordinary user who needs some help with developing own programs for his own use.
User avatar
Capn Odin
Posts: 1352
Joined: 23 Feb 2016, 19:45
Location: Denmark
Contact:

Re: Even more true title case

15 Jun 2016, 20:37

Sorry about the regular expressions. This is unlikely to be the best approach.

Code: Select all

MsgBox, % TitleCase("The quick brown fox jumps at. over the lazy dog")

TitleCase(str){
	lst := ["a", "an", "and", "as", "at", "between", "but", "by", "for", "if", "in", "of", "on", "or", "the", "to", "with", "over"]
	str := Format("{:T}", str)
	
	for index, pre in lst {
		str := RegExReplace(str, "i)\b" pre "\b", pre)
	}
	
	str := Format("{:U}", SubStr(str, 1, 1)) SubStr(str, 2)
	
	pos := 1
	While pos {
		pos := RegExMatch(str, "((?<=[.:?!] )[a-z])|(\b[a-z](?=\w*?[.:?!]))", char)
		if(pos){
			str := SubStr(str, 1, pos - 1) . Format("{:U}", char) . SubStr(str, pos + 1)
		}
	}
	return str
}
Please excuse my spelling I am dyslexic.
User avatar
menteith
Posts: 51
Joined: 04 Feb 2016, 12:22

Re: Even more true title case

16 Jun 2016, 08:01

Capn Odin wrote:Sorry about the regular expressions. This is unlikely to be the best approach.

Code: Select all

MsgBox, % TitleCase("The quick brown fox jumps at. over the lazy dog")

TitleCase(str){
	lst := ["a", "an", "and", "as", "at", "between", "but", "by", "for", "if", "in", "of", "on", "or", "the", "to", "with", "over"]
	str := Format("{:T}", str)
	
	for index, pre in lst {
		str := RegExReplace(str, "i)\b" pre "\b", pre)
	}
	
	str := Format("{:U}", SubStr(str, 1, 1)) SubStr(str, 2)
	
	pos := 1
	While pos {
		pos := RegExMatch(str, "((?<=[.:?!] )[a-z])|(\b[a-z](?=\w*?[.:?!]))", char)
		if(pos){
			str := SubStr(str, 1, pos - 1) . Format("{:U}", char) . SubStr(str, pos + 1)
		}
	}
	return str
}
This works great, thanks! Could you please add a slight modification?

In this string: The quick brown fox jumps at?: over the lazy dog at

The last at (dog at) is not uppper case and it should be because it ends a sentece.

Thanks!
An ordinary user who needs some help with developing own programs for his own use.
User avatar
Capn Odin
Posts: 1352
Joined: 23 Feb 2016, 19:45
Location: Denmark
Contact:

Re: Even more true title case

16 Jun 2016, 15:56

Like this ?

Code: Select all

MsgBox, % TitleCase("The quick brown fox jumps at. over the lazy dog")
MsgBox, % TitleCase("The quick brown fox jumps at?: over the lazy dog at")

TitleCase(str){
	lst := ["a", "an", "and", "as", "at", "between", "but", "by", "for", "if", "in", "of", "on", "or", "the", "to", "with", "over"]
	str := Format("{:T}", str)
	
	for index, pre in lst {
		str := RegExReplace(str, "i)\b" pre "\b", pre)
	}
	
	str := Format("{:U}", SubStr(str, 1, 1)) SubStr(str, 2)
	
	pos := 1
	While pos {
		pos := RegExMatch(str, "((?<=[.:?!] )[a-z])|(\b[a-z](?=\w*?([.:?!]|$)))", char)
		if(pos){
			str := SubStr(str, 1, pos - 1) . Format("{:U}", char) . SubStr(str, pos + 1)
		}
	}
	return str
}
Please excuse my spelling I am dyslexic.
User avatar
menteith
Posts: 51
Joined: 04 Feb 2016, 12:22

Re: Even more true title case

17 Jun 2016, 08:59

Capn Odin wrote:Like this ?[
Perfect, thank you!
An ordinary user who needs some help with developing own programs for his own use.
User avatar
sinkfaze
Posts: 616
Joined: 01 Oct 2013, 08:01

Re: [SOLVED] Even more true title case

17 Jun 2016, 10:57

Code: Select all

MsgBox, %	titleCase("The quick brown fox jumps over the lazy dog, and that's what I've been waiting for!")
MsgBox, %	titleCase("Between the devil and the deep blue sea.")
MsgBox, %	titleCase("To be or not to be.")
return


 
titleCase(str) {

	static	tCase :=	"(?:A(?:nd?|s|t)?|B(?:ut|y)|For|In|Nor|O(?:f|n|r)|Per|T(?:he|o))"
	Loop, 3	; must run at least twice to overcome potential misses from using '\K'
		str :=	RegExReplace(str,"s)[^\.\?\!]\h+\K\b" tCase "\b(?![\.\?\!])","$L0")
	return	str
}
User avatar
menteith
Posts: 51
Joined: 04 Feb 2016, 12:22

Re: [SOLVED] Even more true title case

18 Jun 2016, 04:18

sinkfaze wrote:

Code: Select all

MsgBox, %	titleCase("The quick brown fox jumps over the lazy dog, and that's what I've been waiting for!")
MsgBox, %	titleCase("Between the devil and the deep blue sea.")
MsgBox, %	titleCase("To be or not to be.")
return


 
titleCase(str) {

	static	tCase :=	"(?:A(?:nd?|s|t)?|B(?:ut|y)|For|In|Nor|O(?:f|n|r)|Per|T(?:he|o))"
	Loop, 3	; must run at least twice to overcome potential misses from using '\K'
		str :=	RegExReplace(str,"s)[^\.\?\!]\h+\K\b" tCase "\b(?![\.\?\!])","$L0")
	return	str
}
sinkfaze,

I'd like to have a code that would change a sentence you a title case. So your second msgbox should have a text:

Between the Devil and the Deep Blue Sea.

On my machine your code do not capitalize any word.
An ordinary user who needs some help with developing own programs for his own use.
User avatar
Capn Odin
Posts: 1352
Joined: 23 Feb 2016, 19:45
Location: Denmark
Contact:

Re: [SOLVED] Even more true title case  Topic is solved

18 Jun 2016, 05:47

menteith wrote:
sinkfaze wrote:

Code: Select all

MsgBox, %	titleCase("The quick brown fox jumps over the lazy dog, and that's what I've been waiting for!")
MsgBox, %	titleCase("Between the devil and the deep blue sea.")
MsgBox, %	titleCase("To be or not to be.")
return


 
titleCase(str) {

	static	tCase :=	"(?:A(?:nd?|s|t)?|B(?:ut|y)|For|In|Nor|O(?:f|n|r)|Per|T(?:he|o))"
	Loop, 3	; must run at least twice to overcome potential misses from using '\K'
		str :=	RegExReplace(str,"s)[^\.\?\!]\h+\K\b" tCase "\b(?![\.\?\!])","$L0")
	return	str
}
sinkfaze,

I'd like to have a code that would change a sentence you a title case. So your second msgbox should have a text:

Between the Devil and the Deep Blue Sea.

On my machine your code do not capitalize any word.
Seems fine if you add the line

Code: Select all

str := Format("{:T}", str)

Code: Select all

MsgBox, %	titleCase("The quick brown fox jumps over the lazy dog, and that's what I've been waiting for!")
MsgBox, %	titleCase("Between the devil and the deep blue sea.")
MsgBox, %	titleCase("To be or not to be.")
return

titleCase(str) {
	str := Format("{:T}", str)
	static	tCase :=	"(?:A(?:nd?|s|t)?|B(?:ut|y)|For|In|Nor|O(?:f|n|r)|Per|T(?:he|o))"
	Loop, 3	; must run at least twice to overcome potential misses from using '\K'
		str :=	RegExReplace(str,"s)[^\.\?\!]\h+\K\b" tCase "\b(?![\.\?\!])","$L0")
	return	str
}
Please excuse my spelling I am dyslexic.
User avatar
menteith
Posts: 51
Joined: 04 Feb 2016, 12:22

Re: [SOLVED] Even more true title case

18 Jun 2016, 05:54

Yes, it is working fine now.
An ordinary user who needs some help with developing own programs for his own use.
badWithUserName
Posts: 11
Joined: 03 Feb 2022, 09:07
Contact:

Re: [SOLVED] Even more true title case

03 Oct 2022, 08:02

Capn Odin wrote:
18 Jun 2016, 05:47
menteith wrote:
sinkfaze wrote:

Code: Select all

MsgBox, %	titleCase("The quick brown fox jumps over the lazy dog, and that's what I've been waiting for!")
MsgBox, %	titleCase("Between the devil and the deep blue sea.")
MsgBox, %	titleCase("To be or not to be.")
return


 
titleCase(str) {

	static	tCase :=	"(?:A(?:nd?|s|t)?|B(?:ut|y)|For|In|Nor|O(?:f|n|r)|Per|T(?:he|o))"
	Loop, 3	; must run at least twice to overcome potential misses from using '\K'
		str :=	RegExReplace(str,"s)[^\.\?\!]\h+\K\b" tCase "\b(?![\.\?\!])","$L0")
	return	str
}
sinkfaze,

I'd like to have a code that would change a sentence you a title case. So your second msgbox should have a text:

Between the Devil and the Deep Blue Sea.

On my machine your code do not capitalize any word.
Seems fine if you add the line

Code: Select all

str := Format("{:T}", str)

Code: Select all

MsgBox, %	titleCase("The quick brown fox jumps over the lazy dog, and that's what I've been waiting for!")
MsgBox, %	titleCase("Between the devil and the deep blue sea.")
MsgBox, %	titleCase("To be or not to be.")
return

titleCase(str) {
	str := Format("{:T}", str)
	static	tCase :=	"(?:A(?:nd?|s|t)?|B(?:ut|y)|For|In|Nor|O(?:f|n|r)|Per|T(?:he|o))"
	Loop, 3	; must run at least twice to overcome potential misses from using '\K'
		str :=	RegExReplace(str,"s)[^\.\?\!]\h+\K\b" tCase "\b(?![\.\?\!])","$L0")
	return	str
}
There should be an exception to allow words in all-caps to remain so.
User avatar
Chunjee
Posts: 1419
Joined: 18 Apr 2014, 19:05
Contact:

Re: Even more true title case

04 Oct 2022, 12:21

Is this about AP style titles?
"The quick brown fox jumps over the lazy dog"
image.png
image.png (29 KiB) Viewed 652 times
https://titlecaseconverter.com/
sofista
Posts: 650
Joined: 24 Feb 2020, 13:59
Location: Buenos Aires

Re: [SOLVED] Even more true title case

04 Oct 2022, 14:43

badWithUserName wrote:
03 Oct 2022, 08:02
There should be an exception to allow words in all-caps to remain so.
The Format function does not accept exceptions, so all words are converted to the title case.

So, if you want to keep the words in capital letters—acronyms and similar terms—, you would have to reconvert them to that case. This could be done, for example, with RegEx:

Code: Select all

MsgBox, % titleCase("NASA TV schedule (public channel).")
MsgBox, % titleCase("If you visited this NASA web site from another web site, the URL of the forwarding site.")
MsgBox, % titleCase("A media access control address (MAC address) is a unique identifier assigned to a network interface controller (NIC) for use as a network address in communications within a network segment. This use is common in most IEEE 802 networking technologies. Within the Open Systems Interconnection (OSI) network model, MAC addresses are used in the medium access control protocol sublayer of the data link layer.")
return

titleCase(str) {
	strOld := str
	str := Format("{:T}", str)
	static tCase := "(?:A(?:nd?|s|t)?|B(?:ut|y)|For|In|Nor|O(?:f|n|r)|Per|T(?:he|o))"
	Loop, 3    ; must run at least twice to overcome potential misses from using '\K'
		str := RegExReplace(str,"s)[^\.\?\!]\h+\K\b" tCase "\b(?![\.\?\!])","$L0")
	While RegExMatch(strOld, "O)\b[A-Z]{2,}\b", m, m ? m.Pos + m.Len : 1)    ; Single letter words are ignored.
		str := RegExReplace(str, "i)\b" m[0] "\b", "$U0",, 1, m.Pos)
	return str
}

/* Last output:

A Media Access Control Address (MAC Address) Is a Unique Identifier Assigned to a Network Interface Controller (NIC) for Use as a Network Address in Communications Within a Network Segment. This Use Is Common in Most IEEE 802 Networking Technologies. Within the Open Systems Interconnection (OSI) Network Model, MAC Addresses Are Used in the Medium Access Control Protocol Sublayer of the Data Link Layer.

 */

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Anput, Google [Bot] and 340 guests