Check if a string is all-caps in Emacs lisp?
all. I was wondering if Emacs lisp had a built-in function for checking if a string is made entirely out of capitalized characters. Here is what I'm using right now:
(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)))
It works ok (although it relies on the assumption that I'll only be using ASCII characters), but I was wondering if I was missing some obvious function that I should know about.
In reference to other answers:
Using
upcase
is not a good idea: it will allocate a new string, it will not find if the string has non-alphabetic characters (it seems that you want to forbid that), and it works on integers too (which Emacs uses for characters).Using
string-match
is better -- it fixes all of these issues. As Trey shows, you need to do that whencase-fold-search
isnil
otherwise Emacs might treat it as a case-insensitive search. Butstring-match-p
is even better since it avoids changing the match data. (Emacs keeps that data around after any match, and if you usestring-match
then you'll overwrite it, which might break code that uses your function.)Another issue is the regexp itself. Using
"^...$"
means that Emacs will look for some line with a matching content -- and if your string has newline characters, this might make it return a bogus result. You need to use backslash-unquote and backslash-quote which match only the beginning and end of the string.
So a correct version is:
(defun string-is-capitalized (str)
(let ((case-fold-search nil))
(string-match-p "\\`[A-Z]*\\'" str)))
(BTW, the usual convention in Emacs Lisp is to use a -p
for predicates, as in string-capitalized-p
.)
I don't know of a built-in function that does what you want, but this does:
(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))))
Edit: Changed to use ` and ' as per Eli Barzilay's feedback.
This one lets there be non A-Z chars (not what you asked for, but perhaps interesting):
(defun string-has-no-lowercase (string)
"Return true iff STRING has no lowercase"
(equal (upcase string) string))
External string manipulation library s.el
has s-uppercase?
:
(s-uppercase "GOT TO. THIS AMERICA, MAN.") ; t
(s-uppercase "You cannot lose if you do not play.") ; nil
It is implemented like that:
(defun s-uppercase? (s)
(let ((case-fold-search nil))
(not (string-match-p "[[:lower:]]" s))))
[[:lower:]]
is an Emacs-specific regex corresponding to a lowercase character. string-match-p
accepts a regex and returns an index, starting from which the regex is matched, or returns nil
if there's no match. The idea is to search for a lowercase character in a string, and if none is found, return t
. However string-match-p
ignores case by default, therefore you should temporarily turn off case-fold-search
.
Emacs uses dynamic binding by default, so you can temporarily set global variables to different values inside let
expression. If you set binding to lexical, let would introduce a local copy of case-fold-search
, shadowing the global variable, therefore the above code wouldn't work.
just a wild guess, but what if you make a copy of the string, upcase it (i dont really know much about lisp but a quick google search told there is a "upcase" function, and then check if the two strings are the same? If the are, then the original one must be in all upperscase :P
精彩评论