0

I'm trying to insert a string pathname into a buffer on a Windows machine. The variable holding the string has the right number of backslashes (two) in the directory pathname. I know this because when I "Eval: mypathname" in the minibuffer, the double backslashes are visible.

BUT.. it seems that whenever Emacs evaluates the pathname variable in a function (such as concat, or insert-string), one level of backslashes is stripped out. So what starts out as C:\good\path\slashes in the variable turns into "C:\bad\path\slashes" in the inserted (or concatenated) string in the buffer.

I wrote a small function to try to double the slashes, but all manner of regexp expressions failed for me. I tried doubles, and quadruples, rx-to-string, etc.

Here is my code and a debugger trace and execution trace taken from running the function in a scratch lisp-interaction-mode buffer.

Notice that when the variable value is returned by the function, it still has the right number of slashes. But when I try to use the variable anywhere (in a concat, or in the insert-string calls in the trace, only one slash shows up. And I need TWO slashes to show up in the inserted string.

Any ideas would be appreciated. Thank you

(defun ct-u-path-redouble (path) ;;; This line gives an error: ;;; (setq foo (replace-regexp-in-string "\\" "\\\\" path)) ;;; ;;; Debugger entered--Lisp error: (invalid-regexp "Trailing backslash") ;;; string-match("\\" "C:\\joe\\blow" 0) ;;; replace-regexp-in-string("\\" "\\\\" "C:\\joe\\blow") ;;; (setq foo (replace-regexp-in-string "\\" "\\\\" path)) ;;; ct-u-path-redouble("C:\\joe\\blow") ;;; eval((ct-u-path-redouble "C:\\joe\\blow") nil) (insert-string "\n") (insert-string (concat "\nAfter concat: " path "\n")) path)

(ct-u-path-redouble "C:\joe\blow") After concat: C:joelow (the weird one-slashified ctl chars don't show here) Returned ==> "C:joelow"

(ct-u-path-redouble "C:\\joe\\blow") After concat: C:\joe\blow Returned ==> "C:\\joe\\blow"

7
  • I manually added double (actually quad) slashes in the second example, to show what I see on my screen. When displaying these kinds of things, a poster must allow for the website stripping escaped slashes too... :-)
    – Kevin
    Apr 23, 2016 at 14:37
  • See the Elisp manual, node Syntax for Strings, to learn about using backslashes in Lisp strings.
    – Drew
    Apr 23, 2016 at 15:07
  • Yes, of course again. I've read (and studied) the entire elisp manual, and the elisp Intro, and the Emacs manual, and the code for rx-to-string, and N regexp examples.... and wrote my first Emacs code back in 1982.., and yet this regexp problem STILL stumped me. Frustrating -- so back to simple loops I went, as the solution below shows... I'm still interested in a regexp solution, if someone more knowledgeable than me can figure one out.
    – Kevin
    Apr 23, 2016 at 15:46
  • What are you trying to do? Are you trying to double the backslashes in C:\joe\blow? If so, use this: (replace-regexp-in-string "\\\\" "\\\\" "C:\\joe\\blow").
    – Drew
    Apr 23, 2016 at 16:16
  • 1
    But if you are wanting to use the result in Emacs (including Emacs Lisp) then be aware that you do not need to (and generally should not) use MS Windows file/path syntax - you can just use c:/joe/blow. No need to fiddle with backslashes for Windows file syntax - unless you need that for use ultimately outside Emacs. And in that case you can reintroduce it at the end, when you really need it. In the meantime, i.e., within Emacs, just stick with /, not \.
    – Drew
    Apr 23, 2016 at 16:20

2 Answers 2

2

(ct-u-path-redouble "C:\joe\blow")

This looks like your error. Escape characters in strings are processed when the string is read in the source code by emacs, not when the string is passed to one function or another. Thus you need to have double-backslashes here, and it becomes (ct-u-path-redouble "C:\\joe\\blow")

1
  • You are right, of course. In fact, the second example above shows exactly what you are suggesting -- I passed in double slashes to illustrate the difference in the outputs (which you can see in the outputs -- the first one is weird, and the second one looks "normal" because it displays double slashes in the return value. I will go back and edit the output since doubles are being eaten by the website too...)
    – Kevin
    Apr 23, 2016 at 14:35
0

I finally gave up on regexp's for this problem, and just wrote a little loop that "manually" doubled each slash in the input pathname. Here's my solution, in case someone can use it one day... (I have manually doubled slashes for the website, so what you see is what I actually see on my screen).

(defun double-slash (path) (let ((limit (length path)) i curchar result) (setq i 0) (while (< i limit) ;for each char in input string (setq curchar (substring path i (1+ i))) (cond ((equal curchar "\\") ;double each slash (setq result (concat result "\\" curchar))) (t ;else just copy it over (setq result (concat result curchar)))) (setq i (1+ i))) result))

Based on Drew's comment above, that used 4 slashes in each of the match and replacement (at least visually in his posting), I tried a regexp using 4 to match, and 8 to replace, and it worked. Here is what I see on my screen (I manually added slashes (8 and 16) to get it to look right here). This is a second solution that works.

(insert-string (concat (replace-regexp-in-string "\\\\" "\\\\\\\\" "C:\\joe\\blow") "--hi there")) C:\\joe\\blow--hi therenil

I had tried various combinations of regexp slashes before I first posted (2x2, 2x4, 4x2, 4x4), but I quit after permutations involving up to 4 slashes. I should have kept going, because 4 (match) and 8 (replace) was the combination that worked. Thank you to everyone.

2
  • I have my doubts that this works. Every string you evaluate gets read by the reader. If the reader encounters a backslash, it checks the following character and turns those two characters into a single string character. So, if you passed "foo\bar" as input, "\b" would have been interpreted as bell already and can no longer be turned into a slash and b. Understanding this is fundamental and in no way Emacs-specific.
    – wasamasa
    Apr 23, 2016 at 15:43
  • I agree with what you say about how a single-slashed character gets turned into a bell (or whatever), and how that makes the single slash disappear so it cannot be doubled. My little loop program does indeed work for me, and I confirm that what is shown on the screen above (two instances of two backslashes) is what I see on my emacs screen. So it does what I need it to do, which is -- given a properly slashed directory path as input, will return a slashed string, that when evaluated and inserted into another emacs buffer as the input argument of another function, works.
    – Kevin
    Apr 24, 2016 at 0:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.