Move the remanining two functions in the tools.py file to other source files
This commit is contained in:
@@ -311,3 +311,26 @@ def getGuiItem(theName):
|
|||||||
if qWidget.objectName() == theName:
|
if qWidget.objectName() == theName:
|
||||||
return qWidget
|
return qWidget
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def numberToRoman(numVal, isLower=False):
|
||||||
|
"""Convert an integer to a roman number.
|
||||||
|
"""
|
||||||
|
if not isinstance(numVal, int):
|
||||||
|
return "NAN"
|
||||||
|
if numVal < 1 or numVal > 4999:
|
||||||
|
return "OOR"
|
||||||
|
|
||||||
|
theValues = [
|
||||||
|
(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"),
|
||||||
|
(50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I"),
|
||||||
|
]
|
||||||
|
|
||||||
|
romNum = ""
|
||||||
|
for theDiv, theSym in theValues:
|
||||||
|
n = numVal//theDiv
|
||||||
|
romNum += n*theSym
|
||||||
|
numVal -= n*theDiv
|
||||||
|
if numVal <= 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
return romNum.lower() if isLower else romNum
|
||||||
|
|||||||
+1
-3
@@ -1,17 +1,15 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from nw.core.document import NWDoc
|
from nw.core.document import NWDoc
|
||||||
from nw.core.index import NWIndex
|
from nw.core.index import NWIndex, countWords
|
||||||
from nw.core.project import NWProject
|
from nw.core.project import NWProject
|
||||||
from nw.core.spellcheck import NWSpellCheck, NWSpellEnchant, NWSpellSimple
|
from nw.core.spellcheck import NWSpellCheck, NWSpellEnchant, NWSpellSimple
|
||||||
from nw.core.tohtml import ToHtml
|
from nw.core.tohtml import ToHtml
|
||||||
from nw.core.toodt import ToOdt
|
from nw.core.toodt import ToOdt
|
||||||
from nw.core.tomd import ToMarkdown
|
from nw.core.tomd import ToMarkdown
|
||||||
from nw.core.tools import countWords, numberToRoman
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"countWords",
|
"countWords",
|
||||||
"numberToRoman",
|
|
||||||
"NWDoc",
|
"NWDoc",
|
||||||
"NWIndex",
|
"NWIndex",
|
||||||
"NWProject",
|
"NWProject",
|
||||||
|
|||||||
+63
-3
@@ -5,7 +5,8 @@ novelWriter – Project Index
|
|||||||
Data class for the project index of tags, headers and references
|
Data class for the project index of tags, headers and references
|
||||||
|
|
||||||
File History:
|
File History:
|
||||||
Created: 2019-05-27 [0.1.4]
|
Created: 2019-04-22 [0.0.1] countWords
|
||||||
|
Created: 2019-05-27 [0.1.4] NWIndex
|
||||||
|
|
||||||
This file is a part of novelWriter
|
This file is a part of novelWriter
|
||||||
Copyright 2018–2021, Veronica Berglyd Olsen
|
Copyright 2018–2021, Veronica Berglyd Olsen
|
||||||
@@ -32,10 +33,10 @@ import os
|
|||||||
from time import time
|
from time import time
|
||||||
|
|
||||||
from nw.constants import (
|
from nw.constants import (
|
||||||
nwFiles, nwKeyWords, nwItemType, nwItemClass, nwItemLayout, nwAlert
|
nwFiles, nwKeyWords, nwItemType, nwItemClass, nwItemLayout, nwAlert,
|
||||||
|
nwUnicode
|
||||||
)
|
)
|
||||||
from nw.core.document import NWDoc
|
from nw.core.document import NWDoc
|
||||||
from nw.core.tools import countWords
|
|
||||||
from nw.common import isHandle, isTitleTag, isItemClass, isItemLayout
|
from nw.common import isHandle, isTitleTag, isItemClass, isItemLayout
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -906,3 +907,62 @@ class NWIndex():
|
|||||||
return
|
return
|
||||||
|
|
||||||
# END Class NWIndex
|
# END Class NWIndex
|
||||||
|
|
||||||
|
# =============================================================================================== #
|
||||||
|
# Simple Word Counter
|
||||||
|
# =============================================================================================== #
|
||||||
|
|
||||||
|
def countWords(theText):
|
||||||
|
"""Count words in a piece of text, skipping special syntax and
|
||||||
|
comments.
|
||||||
|
"""
|
||||||
|
charCount = 0
|
||||||
|
wordCount = 0
|
||||||
|
paraCount = 0
|
||||||
|
prevEmpty = True
|
||||||
|
|
||||||
|
# We need to treat dashes as word separators for counting words.
|
||||||
|
# The check+replace apprach is much faster that direct replace for
|
||||||
|
# large texts, and a bit slower for small texts, but in the latter
|
||||||
|
# case it doesn't matter.
|
||||||
|
if nwUnicode.U_ENDASH in theText:
|
||||||
|
theText = theText.replace(nwUnicode.U_ENDASH, " ")
|
||||||
|
if nwUnicode.U_EMDASH in theText:
|
||||||
|
theText = theText.replace(nwUnicode.U_EMDASH, " ")
|
||||||
|
|
||||||
|
for aLine in theText.splitlines():
|
||||||
|
|
||||||
|
countPara = True
|
||||||
|
theLen = len(aLine)
|
||||||
|
|
||||||
|
if theLen == 0:
|
||||||
|
prevEmpty = True
|
||||||
|
continue
|
||||||
|
if aLine[0] == "@" or aLine[0] == "%":
|
||||||
|
continue
|
||||||
|
|
||||||
|
if aLine[0:5] == "#### ":
|
||||||
|
wordCount -= 1
|
||||||
|
charCount -= 5
|
||||||
|
countPara = False
|
||||||
|
elif aLine[0:4] == "### ":
|
||||||
|
wordCount -= 1
|
||||||
|
charCount -= 4
|
||||||
|
countPara = False
|
||||||
|
elif aLine[0:3] == "## ":
|
||||||
|
wordCount -= 1
|
||||||
|
charCount -= 3
|
||||||
|
countPara = False
|
||||||
|
elif aLine[0:2] == "# ":
|
||||||
|
wordCount -= 1
|
||||||
|
charCount -= 2
|
||||||
|
countPara = False
|
||||||
|
|
||||||
|
wordCount += len(aLine.split())
|
||||||
|
charCount += theLen
|
||||||
|
if countPara and prevEmpty:
|
||||||
|
paraCount += 1
|
||||||
|
|
||||||
|
prevEmpty = not countPara
|
||||||
|
|
||||||
|
return charCount, wordCount, paraCount
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ from functools import partial
|
|||||||
from PyQt5.QtCore import QCoreApplication, QRegularExpression
|
from PyQt5.QtCore import QCoreApplication, QRegularExpression
|
||||||
|
|
||||||
from nw.core.document import NWDoc
|
from nw.core.document import NWDoc
|
||||||
from nw.core.tools import numberToRoman
|
from nw.common import numberToRoman
|
||||||
from nw.constants import nwConst, nwUnicode, nwItemLayout, nwItemType, nwRegEx
|
from nw.constants import nwConst, nwUnicode, nwItemLayout, nwItemType, nwRegEx
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|||||||
@@ -1,118 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
novelWriter – Various Tools
|
|
||||||
===========================
|
|
||||||
Various core tool functions
|
|
||||||
|
|
||||||
File History:
|
|
||||||
Created: 2019-04-22 [0.0.1] countWords
|
|
||||||
Created: 2020-07-05 [0.10.0] numberToRoman
|
|
||||||
|
|
||||||
This file is a part of novelWriter
|
|
||||||
Copyright 2018–2021, Veronica Berglyd Olsen
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from nw.constants import nwUnicode
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# =============================================================================================== #
|
|
||||||
# Simple Word Counter
|
|
||||||
# =============================================================================================== #
|
|
||||||
|
|
||||||
def countWords(theText):
|
|
||||||
"""Count words in a piece of text, skipping special syntax and
|
|
||||||
comments.
|
|
||||||
"""
|
|
||||||
charCount = 0
|
|
||||||
wordCount = 0
|
|
||||||
paraCount = 0
|
|
||||||
prevEmpty = True
|
|
||||||
|
|
||||||
# We need to treat dashes as word separators for counting words.
|
|
||||||
# The check+replace apprach is much faster that direct replace for
|
|
||||||
# large texts, and a bit slower for small texts, but in the latter
|
|
||||||
# case it doesn't matter.
|
|
||||||
if nwUnicode.U_ENDASH in theText:
|
|
||||||
theText = theText.replace(nwUnicode.U_ENDASH, " ")
|
|
||||||
if nwUnicode.U_EMDASH in theText:
|
|
||||||
theText = theText.replace(nwUnicode.U_EMDASH, " ")
|
|
||||||
|
|
||||||
for aLine in theText.splitlines():
|
|
||||||
|
|
||||||
countPara = True
|
|
||||||
theLen = len(aLine)
|
|
||||||
|
|
||||||
if theLen == 0:
|
|
||||||
prevEmpty = True
|
|
||||||
continue
|
|
||||||
if aLine[0] == "@" or aLine[0] == "%":
|
|
||||||
continue
|
|
||||||
|
|
||||||
if aLine[0:5] == "#### ":
|
|
||||||
wordCount -= 1
|
|
||||||
charCount -= 5
|
|
||||||
countPara = False
|
|
||||||
elif aLine[0:4] == "### ":
|
|
||||||
wordCount -= 1
|
|
||||||
charCount -= 4
|
|
||||||
countPara = False
|
|
||||||
elif aLine[0:3] == "## ":
|
|
||||||
wordCount -= 1
|
|
||||||
charCount -= 3
|
|
||||||
countPara = False
|
|
||||||
elif aLine[0:2] == "# ":
|
|
||||||
wordCount -= 1
|
|
||||||
charCount -= 2
|
|
||||||
countPara = False
|
|
||||||
|
|
||||||
wordCount += len(aLine.split())
|
|
||||||
charCount += theLen
|
|
||||||
if countPara and prevEmpty:
|
|
||||||
paraCount += 1
|
|
||||||
|
|
||||||
prevEmpty = not countPara
|
|
||||||
|
|
||||||
return charCount, wordCount, paraCount
|
|
||||||
|
|
||||||
# =============================================================================================== #
|
|
||||||
# Convert an Integer to a Roman Number
|
|
||||||
# =============================================================================================== #
|
|
||||||
|
|
||||||
def numberToRoman(numVal, isLower=False):
|
|
||||||
"""Convert an integer to a roman number.
|
|
||||||
"""
|
|
||||||
if not isinstance(numVal, int):
|
|
||||||
return "NAN"
|
|
||||||
if numVal < 1 or numVal > 4999:
|
|
||||||
return "OOR"
|
|
||||||
|
|
||||||
theValues = [
|
|
||||||
(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"),
|
|
||||||
(50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5, "V"), (4, "IV"), (1, "I"),
|
|
||||||
]
|
|
||||||
|
|
||||||
romNum = ""
|
|
||||||
for theDiv, theSym in theValues:
|
|
||||||
n = numVal//theDiv
|
|
||||||
romNum += n*theSym
|
|
||||||
numVal -= n*theDiv
|
|
||||||
if numVal <= 0:
|
|
||||||
break
|
|
||||||
|
|
||||||
return romNum.lower() if isLower else romNum
|
|
||||||
@@ -37,7 +37,7 @@ from PyQt5.QtWidgets import (
|
|||||||
|
|
||||||
from nw.gui.custom import PagedDialog, QSwitch
|
from nw.gui.custom import PagedDialog, QSwitch
|
||||||
from nw.constants import nwUnicode
|
from nw.constants import nwUnicode
|
||||||
from nw.core import numberToRoman
|
from nw.common import numberToRoman
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ from nw.common import (
|
|||||||
checkString, checkBool, checkInt, colRange, formatInt, transferCase,
|
checkString, checkBool, checkInt, colRange, formatInt, transferCase,
|
||||||
fuzzyTime, checkHandle, formatTimeStamp, formatTime, hexToInt,
|
fuzzyTime, checkHandle, formatTimeStamp, formatTime, hexToInt,
|
||||||
makeFileNameSafe, isHandle, isTitleTag, isItemClass, isItemType,
|
makeFileNameSafe, isHandle, isTitleTag, isItemClass, isItemType,
|
||||||
isItemLayout
|
isItemLayout, numberToRoman
|
||||||
)
|
)
|
||||||
from tools import cmpList
|
from tools import cmpList
|
||||||
|
|
||||||
@@ -325,3 +325,30 @@ def testBaseCommon_MakeFileNameSafe():
|
|||||||
assert makeFileNameSafe("aaaa bbbb") == "aaaa bbbb"
|
assert makeFileNameSafe("aaaa bbbb") == "aaaa bbbb"
|
||||||
|
|
||||||
# END Test testBaseCommon_MakeFileNameSafe
|
# END Test testBaseCommon_MakeFileNameSafe
|
||||||
|
|
||||||
|
@pytest.mark.core
|
||||||
|
def testBaseCommon_RomanNumbers():
|
||||||
|
"""Test conversion of integers to Roman numbers.
|
||||||
|
"""
|
||||||
|
assert numberToRoman(None, False) == "NAN"
|
||||||
|
assert numberToRoman(0, False) == "OOR"
|
||||||
|
assert numberToRoman(1, False) == "I"
|
||||||
|
assert numberToRoman(2, False) == "II"
|
||||||
|
assert numberToRoman(3, False) == "III"
|
||||||
|
assert numberToRoman(4, False) == "IV"
|
||||||
|
assert numberToRoman(5, False) == "V"
|
||||||
|
assert numberToRoman(6, False) == "VI"
|
||||||
|
assert numberToRoman(7, False) == "VII"
|
||||||
|
assert numberToRoman(8, False) == "VIII"
|
||||||
|
assert numberToRoman(9, False) == "IX"
|
||||||
|
assert numberToRoman(10, False) == "X"
|
||||||
|
assert numberToRoman(14, False) == "XIV"
|
||||||
|
assert numberToRoman(42, False) == "XLII"
|
||||||
|
assert numberToRoman(99, False) == "XCIX"
|
||||||
|
assert numberToRoman(142, False) == "CXLII"
|
||||||
|
assert numberToRoman(542, False) == "DXLII"
|
||||||
|
assert numberToRoman(999, False) == "CMXCIX"
|
||||||
|
assert numberToRoman(2010, False) == "MMX"
|
||||||
|
assert numberToRoman(999, True) == "cmxcix"
|
||||||
|
|
||||||
|
# END Test testBaseCommon_RomanNumbers
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ from shutil import copyfile
|
|||||||
from tools import cmpFiles
|
from tools import cmpFiles
|
||||||
|
|
||||||
from nw.core.project import NWProject
|
from nw.core.project import NWProject
|
||||||
from nw.core.index import NWIndex
|
from nw.core.index import NWIndex, countWords
|
||||||
from nw.constants import nwItemClass, nwItemLayout
|
from nw.constants import nwItemClass, nwItemLayout
|
||||||
|
|
||||||
@pytest.mark.core
|
@pytest.mark.core
|
||||||
@@ -1161,3 +1161,34 @@ def testCoreIndex_CheckTextCounts(dummyGUI):
|
|||||||
theIndex._checkTextCounts()
|
theIndex._checkTextCounts()
|
||||||
|
|
||||||
# END Test testCoreIndex_CheckTextCounts
|
# END Test testCoreIndex_CheckTextCounts
|
||||||
|
|
||||||
|
@pytest.mark.core
|
||||||
|
def testCoreIndex_CountWords():
|
||||||
|
"""Test the word counter and the exclusion filers.
|
||||||
|
"""
|
||||||
|
testText = (
|
||||||
|
"# Heading One\n"
|
||||||
|
"## Heading Two\n"
|
||||||
|
"### Heading Three\n"
|
||||||
|
"#### Heading Four\n"
|
||||||
|
"\n"
|
||||||
|
"@tag: value\n"
|
||||||
|
"\n"
|
||||||
|
"% A comment that should n ot be counted.\n"
|
||||||
|
"\n"
|
||||||
|
"The first paragraph.\n"
|
||||||
|
"\n"
|
||||||
|
"The second paragraph.\n"
|
||||||
|
"\n"
|
||||||
|
"\n"
|
||||||
|
"The third paragraph.\n"
|
||||||
|
"\n"
|
||||||
|
"Dashes\u2013and even longer\u2014dashes."
|
||||||
|
)
|
||||||
|
cC, wC, pC = countWords(testText)
|
||||||
|
|
||||||
|
assert cC == 138
|
||||||
|
assert wC == 22
|
||||||
|
assert pC == 4
|
||||||
|
|
||||||
|
# END Test testCoreIndex_CountWords
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
novelWriter – Core Tools Tester
|
|
||||||
===============================
|
|
||||||
|
|
||||||
This file is a part of novelWriter
|
|
||||||
Copyright 2018–2021, Veronica Berglyd Olsen
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but
|
|
||||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
|
|
||||||
from nw.core.tools import countWords, numberToRoman
|
|
||||||
|
|
||||||
@pytest.mark.core
|
|
||||||
def testCoreTools_CountWords():
|
|
||||||
"""Test the word counter and the exclusion filers.
|
|
||||||
"""
|
|
||||||
testText = (
|
|
||||||
"# Heading One\n"
|
|
||||||
"## Heading Two\n"
|
|
||||||
"### Heading Three\n"
|
|
||||||
"#### Heading Four\n"
|
|
||||||
"\n"
|
|
||||||
"@tag: value\n"
|
|
||||||
"\n"
|
|
||||||
"% A comment that should n ot be counted.\n"
|
|
||||||
"\n"
|
|
||||||
"The first paragraph.\n"
|
|
||||||
"\n"
|
|
||||||
"The second paragraph.\n"
|
|
||||||
"\n"
|
|
||||||
"\n"
|
|
||||||
"The third paragraph.\n"
|
|
||||||
"\n"
|
|
||||||
"Dashes\u2013and even longer\u2014dashes."
|
|
||||||
)
|
|
||||||
cC, wC, pC = countWords(testText)
|
|
||||||
|
|
||||||
assert cC == 138
|
|
||||||
assert wC == 22
|
|
||||||
assert pC == 4
|
|
||||||
|
|
||||||
# END Test testCoreTools_CountWords
|
|
||||||
|
|
||||||
@pytest.mark.core
|
|
||||||
def testCoreTools_RomanNumbers():
|
|
||||||
"""Test conversion of integers to Roman numbers.
|
|
||||||
"""
|
|
||||||
assert numberToRoman(None, False) == "NAN"
|
|
||||||
assert numberToRoman(0, False) == "OOR"
|
|
||||||
assert numberToRoman(1, False) == "I"
|
|
||||||
assert numberToRoman(2, False) == "II"
|
|
||||||
assert numberToRoman(3, False) == "III"
|
|
||||||
assert numberToRoman(4, False) == "IV"
|
|
||||||
assert numberToRoman(5, False) == "V"
|
|
||||||
assert numberToRoman(6, False) == "VI"
|
|
||||||
assert numberToRoman(7, False) == "VII"
|
|
||||||
assert numberToRoman(8, False) == "VIII"
|
|
||||||
assert numberToRoman(9, False) == "IX"
|
|
||||||
assert numberToRoman(10, False) == "X"
|
|
||||||
assert numberToRoman(14, False) == "XIV"
|
|
||||||
assert numberToRoman(42, False) == "XLII"
|
|
||||||
assert numberToRoman(99, False) == "XCIX"
|
|
||||||
assert numberToRoman(142, False) == "CXLII"
|
|
||||||
assert numberToRoman(542, False) == "DXLII"
|
|
||||||
assert numberToRoman(999, False) == "CMXCIX"
|
|
||||||
assert numberToRoman(2010, False) == "MMX"
|
|
||||||
assert numberToRoman(999, True) == "cmxcix"
|
|
||||||
|
|
||||||
# END Test testCoreTools_RomanNumbers
|
|
||||||
Reference in New Issue
Block a user