这可能是一个疯狂的场景,但只是想知道有什么方法可以在没有分隔符的情况下将单词中的几个字符大写(以识别要大写的字符)
例如:- I/P 候选人名字候选人城市
O/P 候选人名字 候选人城市
答案1
我写了下面的程序TXRLisp 用来解决这个问题。这依赖于/usr/share/dict/words
可用的字典文件;另外,它还添加了一些自己的单词,这些单词是计算机程序中标识符中常见的缩写。我找到了其中的一些来源并自己添加了一些。
该程序使用 TXR Lisp 的内置 trie 工具从字典中构建一个 trie。 trie 结构对于大型字典的优化很差,并且相当消耗内存,并且代码有点笨拙;它可以从精简中受益。
在最高级别,该函数camelize
返回一个它认为好的单词的驼峰式大小写版本列表(通常只有一个),试图实现该问题的要求。
我就这样留下了;只是我们可以使用 REPL 探索的一个函数;没有封装的实用程序:
$ txr -i camel.tl
Do not operate heavy equipment or motor vehicles while using TXR.
1> (camelize "shellexecuteex")
("ShellExecuteEx")
2> (camelize "getenvptr")
("GetEnvPtr")
3> (camelize "hownowbrowncow")
("HowNowBrownCow")
4> (camelize "arcanthill")
("ArcAnthill")
5> (camelize "calcmd5digest")
("CalcMd5Digest")
6> (camelize "themother")
("TheMother" "ThemOther")
它工作原理的核心是break-word
返回一个单词所有可能的分割列表的函数。
该算法是递归的,工作原理大致如下:
尝试查找字典中找到的给定单词的所有前缀。例如,给我们
albumin
前缀a
、alb
和album
。albumin
如果找到一个或多个前缀,则递归:对于每个前缀,找到将后缀分解为单词的可能方法,并对每种可能性添加前缀。
如果未找到前缀,则该单词以字典中没有的垃圾字符开头。在这种情况下,扫描该单词的连续位置以查看是否出现字典单词。例如,如果我们有
34albumin
,则3
和4
将被跳过,然后a
找到。当垃圾被分隔后,将其视为一个单词:对单词的其余部分进行递归并组合,与步骤 2 类似。
该camelize
函数获取break-word
并选择一组候选细分,如下所示。
每个单词的划分都分配有一个由一对数字组成的排序键:垃圾数量该词的划分,以及长度。垃圾数量是指不是来自词典的字符数。长度是该词划分中的元素数量。
我们根据 1 中确定的键对细分列表进行排序。包含更多垃圾字符的单词细分被认为是严格更差的。当两个单词细分包含相同数量的垃圾字符时,其中包含更多碎片的单词被认为更差。例如,在 的情况下
themother
,有两个故障the
mother
和them
other
。它们都具有零垃圾字符:它们的垃圾数量为零。而且它们都是两个元素长,所以是等价的。该算法选择两者。在第2步排序后,我们按等效键对排序进行分组,并选择最佳组。然后我们从该组中生成 CamelCase。
垃圾在单词细分中通过列表注释来识别:它看起来像(:junk "grf")
。例如cat3dog
将产生如下所示的故障("cat" (:junk "3") "dog")
。junk-quantity
和函数中的代码camelize
使用一些结构模式匹配来处理这个问题。
长输入需要一些时间:例如,这个需要几秒钟。可以通过编译代码来加快速度。该break-word
函数也可以从记忆中受益,因为递归搜索将由于尝试加起来相同的前缀组合而计算出许多相同的后缀细分。
1> (camelize "nowisthetimeforallgoodmentocometotheaidoftheircountry")
("NoWistHeTimeForAllGoodMenToComeToTheAidOfTheirCountry"
"NoWistHeTimeForAllGoodMenToComeToTheAidOftHeirCountry"
"NoWistHeTimeForAllGoodMenToComeTotHeAidOfTheirCountry"
"NoWistHeTimeForAllGoodMenToComeTotHeAidOftHeirCountry"
"NoWistHeTimeForaLlGoodMenToComeToTheAidOfTheirCountry"
"NoWistHeTimeForaLlGoodMenToComeToTheAidOftHeirCountry"
"NoWistHeTimeForaLlGoodMenToComeTotHeAidOfTheirCountry"
"NoWistHeTimeForaLlGoodMenToComeTotHeAidOftHeirCountry"
"NowIsTheTimeForAllGoodMenToComeToTheAidOfTheirCountry"
"NowIsTheTimeForAllGoodMenToComeToTheAidOftHeirCountry"
"NowIsTheTimeForAllGoodMenToComeTotHeAidOfTheirCountry"
"NowIsTheTimeForAllGoodMenToComeTotHeAidOftHeirCountry"
"NowIsTheTimeForaLlGoodMenToComeToTheAidOfTheirCountry"
"NowIsTheTimeForaLlGoodMenToComeToTheAidOftHeirCountry"
"NowIsTheTimeForaLlGoodMenToComeTotHeAidOfTheirCountry"
"NowIsTheTimeForaLlGoodMenToComeTotHeAidOftHeirCountry")
(为什么会有这个发现ForaLlGood
?因为ll
在计算标识符时被用作缩写,因此被列为一个单词。)
现在只是代码:
(defvarl %dict% "/usr/share/dict/words")
(defun trie-dict (dict)
(let ((trie (make-trie)))
(each ((word dict))
(if (> (len word) 2)
(trie-add trie word t)))
(each ((word '#"a I ad am an as at ax be by do ex go he hi \
id if in is it lo me mi my no of oh on or \
ow ox pa pi re so to un up us we abs act \
addr alloc alt arg attr app arr auth avg \
bat bg bin bool brk btn buf char calc cb \
cert cfg ch chr circ clr cmd cmp cnt \
concat conf config conn cont conv col coll \
com cord coord cos csum ctrl ctx cur cpy \
db dbg dec def def del dest dev dev diff \
dir dis disp doc drv dsc dt en enc env eq err \
expr exch exchg fig fmt fp func ge gen gt hex \
hdr hor hw id idx iface img inc info init int \
lang lat lib le len ll lon math max mem mcu \
mid min misc mng mod msg ne net num obj ord \
op os param pic pos posix pred pref prev proc \
prof ptr pwr px qry rand rect recv rem res \
ret rev req rng rx sem sel seq stat std str \
sin sqrt src swp sync temp temp tgl tmp tmr \
tran trans ts tx txt unix usr val var vert win \
xform xmit xref xtract"))
(trie-add trie word t))
trie))
(defvarl %trie% (trie-dict (file-get-lines %dict%)))
(defun break-word (trie word)
(iflet ((lw (len word))
((plusp lw)))
(build
(let ((i 0)
(cursor (trie-lookup-begin trie)))
(whilet ((next (if (< i lw)
(trie-lookup-feed-char cursor [word i]))))
(inc i)
(set cursor next)
(if (trie-value-at next)
(let ((first-word [word 0..i])
(rest-words (break-word trie [word i..:])))
(if rest-words
(each ((rest-wordlist rest-words))
(add ^(,first-word ,*rest-wordlist)))
(add ^(,first-word))))))
(unless (get)
(for ((j 1)) ((and (< j lw) (not (get)))) ((inc j))
(let ((i j)
(cursor (trie-lookup-begin trie)))
(whilet ((next (if (and (< i lw) (not (get)))
(trie-lookup-feed-char cursor [word i]))))
(inc i)
(set cursor next)
(if (trie-value-at next)
(let ((junk-word [word 0..j])
(rest-words (break-word trie [word j..:])))
(each ((rest-wordlist rest-words))
(add ^((:junk ,junk-word) ,*rest-wordlist)))))))))
(unless (get)
(add ^((:junk ,word))))))))
(defun junk-quantity (broken-word)
(let ((char-count 0))
(each ((word broken-word))
(if-match (:junk @str) word
(inc char-count (len str))))
char-count))
(defun camelize (word)
(if (empty word)
word
(flow (break-word %trie% word)
(mapcar [juxt [juxt junk-quantity len] use])
(sort @1 : first)
(partition-by first)
first
(mapcar second)
(mapcar
(opip (mapcar (do match @(or `@{x 1}@y`
(:junk `@{x 1}@y`))
@1
`@(upcase-str x)@y`))
cat-str)))))