【问题标题】:Check if a string is all-caps in Emacs lisp?检查 Emacs lisp 中的字符串是否全大写?
【发布时间】:2010-01-25 02:13:31
【问题描述】:

全部。我想知道 Emacs lisp 是否有一个内置函数来检查字符串是否完全由大写字符组成。这是我现在使用的:

(setq capital-letters (string-to-list "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))

(defun chars-are-capitalized (list-of-characters)
  "Returns true if every character in a list of characters is a capital         
letter. As a special case, the empty list returns true."
  (cond
   ((equal list-of-characters nil) t)
   ((not (member (car list-of-characters) capital-letters)) nil)
   (t (chars-are-capitalized (cdr list-of-characters)))))

(defun string-is-capitalized (string)
  "Returns true if every character in a string is a capital letter. The         
empty string returns true."
  (chars-are-capitalized (string-to-list string)))

它工作正常(虽然它依赖于我将只使用 ASCII 字符的假设),但我想知道我是否遗漏了一些我应该知道的明显功能。

【问题讨论】:

    标签: emacs lisp elisp capitalization


    【解决方案1】:

    参考其他答案:

    1. 使用upcase不是一个好主意:它会分配一个新的字符串,如果字符串有非字母字符,它不会找到(看来你要禁止那),它也适用于整数(Emacs 用于字符)。

    2. 使用string-match 更好——它可以解决所有这些问题。正如 Trey 所示,当 case-fold-searchnil 时,您需要这样做,否则 Emacs 可能会将其视为不区分大小写的搜索。但是string-match-p 更好,因为它避免了更改匹配数据。 (Emacs 会在任何匹配后保留该数据,如果您使用 string-match,那么您将覆盖它,这可能会破坏使用您的函数的代码。)

    3. 另一个问题是正则表达式本身。使用"^...$" 意味着Emacs 将查找具有匹配内容的某些行——如果您的字符串有换行符,这可能会使其返回虚假结果。您需要使用仅匹配字符串开头和结尾的反斜杠取消引用和反斜杠引用。

    所以正确的版本是:

    (defun string-is-capitalized (str)
      (let ((case-fold-search nil))
        (string-match-p "\\`[A-Z]*\\'" str)))
    

    (顺便说一句,Emacs Lisp 中通常的约定是使用-p 表示谓词,如string-capitalized-p。)

    【讨论】:

    • 而不是A-Z 我想你想在正则表达式中使用[:upper:]
    • 嗯,(1)我不喜欢[:upper:],因为它往往意味着不同的东西(在某些情况下是任何unicode大写字符,在其他情况下只有A-Z)所以我更喜欢尽可能明确的形式; (2) 我按照最初的要求回答了这个问题,该代码仅限于A-Z; (3) 正则表达式的使用已经足够好,因此随机绕过者在需要时自然会使用其他东西; (4) 最后,请注意我使用了“a 正确版本”并避免了正则表达式讨论以使其更加集中......
    【解决方案2】:

    我不知道有什么内置函数可以满足您的要求,但它可以:

    (defun string-all-caps-p (string)
      "Return non-nil iff STRING is all capital letters."
      (save-match-data
        (let ((case-fold-search nil))
          (string-match "\\`[A-Z]+\\'" string))))
    

    编辑:根据Eli Barzilay 的反馈更改为使用 ` 和 '。

    这个允许有非 A-Z 字符(不是你要求的,但也许很有趣):

    (defun string-has-no-lowercase (string)
      "Return true iff STRING has no lowercase"
      (equal (upcase string) string))
    

    【讨论】:

    • 第一个是有道理的;我应该想到一个正则表达式。我已经考虑过检查(相等字符串(大写字符串)),但如果字符串有任何非字母字母,我确实需要它返回 false。
    • 对于第一个,您可能希望将其包装在 save-match-data 调用中,这样任何现有的正则表达式匹配数据都不会被覆盖。
    【解决方案3】:

    外部字符串操作库s.els-uppercase?

    (s-uppercase "GOT TO. THIS AMERICA, MAN.") ; t
    (s-uppercase "You cannot lose if you do not play.") ; nil
    

    它是这样实现的:

    (defun s-uppercase? (s)
      (let ((case-fold-search nil))
        (not (string-match-p "[[:lower:]]" s))))
    

    [[:lower:]] 是一个Emacs-specific regex,对应一个小写字符。 string-match-p 接受一个正则表达式并返回一个索引,从该索引开始匹配正则表达式,如果没有匹配则返回 nil。这个想法是在字符串中搜索一个小写字符,如果没有找到,返回t。但是string-match-p默认忽略大小写,所以你应该暂时关闭case-fold-search

    Emacs 默认使用dynamic binding,因此您可以在let 表达式中临时将全局变量设置为不同的值。如果您将绑定设置为词法,let 将引入 case-fold-search 的本地副本,隐藏全局变量,因此上述代码将不起作用。

    【讨论】:

    • 这为我解决了一个主要的困惑,谢谢。一个小评论:在我的系统上,无论函数是词法还是动态范围,这个函数都可以工作。不知case-fold-search是不是所谓的特殊变量,也就是说is会继续被动态绑定。 (详情请参阅gnu.org/software/emacs/manual/html_node/elisp/…。)
    【解决方案4】:

    只是一个疯狂的猜测,但是如果你复制一个字符串,把它大写怎么办(我对 lisp 不太了解,但是一个快速的谷歌搜索告诉有一个“大写”函数,然后检查两个字符串是否是一样的吗?如果是,那么原始的必须全部大写:P

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-04-19
      • 1970-01-01
      • 2010-10-01
      • 2017-12-24
      • 2014-08-13
      • 2014-03-26
      • 1970-01-01
      相关资源
      最近更新 更多