<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Is a filename legal?]]></title><description><![CDATA[<p dir="auto">Hello, <strong>All</strong>,</p>
<p dir="auto">Quite by <strong>chance</strong>, I came across this article :</p>
<p dir="auto"><em>How do I check if a given string is a legal/valid file name under Windows?</em></p>
<p dir="auto"><a href="https://stackoverflow.com/questions/62771" rel="nofollow ugc">https://stackoverflow.com/questions/62771</a></p>
<p dir="auto">So, I decided to run a <strong>few</strong> tests and <strong>“rework”</strong> the different regular expressions suggested as answers !</p>
<p dir="auto">I finally came up with the <strong>multi-lines</strong> regex, below :</p>
<pre><code class="language-diff">(?xi-s)
^
("?)
(?!
  (?: PRN | AUX | NUL | CON | COM (?!0) \d | LPT (?!0) \d )
  (?: \. .+ )? \1 $
)
[^\x00-\x1F"*/:&lt;&gt;?\\|\x7F]+
(?&lt;! [\x00-\x20.] )
\1
$
</code></pre>
<hr />
<p dir="auto"><strong>Three</strong> remarks :</p>
<ul>
<li>
<p dir="auto">This regex considers that cases <strong><code>"abcd.txt</code></strong> and <strong><code>abcd.txt"</code></strong> are <strong>invalid</strong>. In other words, the <strong>legal</strong> syntaxes are <strong><code>abcd.txt</code></strong> or <strong><code>"abcd.txt"</code></strong> <em>ONLY</em>. To do so, I use as <strong>group <code>1</code></strong> the string <strong><code>"?</code></strong>. Thus :</p>
<ul>
<li>
<p dir="auto">If a <strong><code>"</code></strong> character begins the file name, the <strong>group 1</strong> exists and the <strong>two</strong> back-references <strong><code>\1</code></strong> represents the character <strong><code>"</code></strong> itself</p>
</li>
<li>
<p dir="auto">If <strong>no</strong> <strong><code>"</code></strong> character begins current file name, the <strong>group 1</strong> exists too but, as well as the back-references, it represents only an <strong>empty</strong> string</p>
</li>
</ul>
</li>
<li>
<p dir="auto">The <strong>reserved</strong> names, like <strong><code>CON</code></strong> or <strong><code>AUX</code></strong>, are also <strong>reserved</strong> when written <strong>lower-case</strong> as <strong><code>con</code></strong> or <strong><code>aux</code></strong>  ! Thus, the <strong>insensitive</strong> <strong><code>i</code></strong> flag</p>
</li>
<li>
<p dir="auto">In the <strong>suggested</strong> regexes, they use the <strong>final</strong> negative look-behind <strong><code>(?&lt;! [\s.] )</code></strong>. However, I verified that <em>ANY</em> char over <strong><code>\x20</code></strong>, from the <strong><code>\s</code></strong> range, like <strong><code>\xA0</code></strong>, <strong><code>\x{2007}</code></strong>, <strong><code>\x{205F}</code></strong> …  or even a char <strong>outside</strong> <strong><code>\s</code></strong> like <strong><code>\x97</code></strong>, <strong><code>\x9F</code></strong> … , may be <strong>added</strong> as <strong>trailing</strong> chars of a filename ! Thus, I preferred the <strong><code>(?&lt;! [\x00-\x20.] )</code></strong> syntax</p>
</li>
</ul>
<hr />
<p dir="auto">To insert a character, from the <strong>six</strong> characters <strong><code>SPACE</code></strong>  <strong><code>&amp;</code></strong>  <strong><code>,</code></strong>  <strong><code>;</code></strong>  <strong><code>=</code></strong>  <strong><code>^</code></strong> and, especially, at <strong>beginning</strong> of the filename :</p>
<ul>
<li>
<p dir="auto">Rename the filename between <strong>two</strong> <em>DOUBLES QUOTES</em> when within <strong>DOS</strong> or within any application like <strong>N++</strong> or else</p>
</li>
<li>
<p dir="auto">Except for the <strong>space</strong> char, you may also simply use the <strong>rename</strong> option of Microsoft <strong><code>Explorer</code></strong> to insert any <strong>allowed</strong> character</p>
</li>
</ul>
<hr />
<p dir="auto">For information :</p>
<pre><code class="language-diff">ALWAYS forbidden               :       \x00-\x1F    "    *    /    :    &lt;    &gt;    ?    \    |    \x7F

                               :         .    at the END of file name
                                   
                               :       SPACE  at the END of file name

                               :       ALL DOTS file name

                               :       PRN    AUX    NUL

                               :       COM1    COM2    com3    COM4    COM5    COM6    COM7    COM8    COM9    COM¹    COM²    COM³

                               :       com1    com2    com3    com4    com5    com6    com7    com8    com9    com¹    com²    com³

                               :       LPT1    LPT2    LPT3    LPT4    LPT5    lpt6    LPT7    LPT8    LPT9    LPT¹    LPT²    LPT³

                               :       lpt1    lpt2    lpt3    lpt4    lpt5    lpt6    lpt7    lpt8    lpt9    lpt¹    lpt²    lpt³


Allowed WITHIN  double quotes  :       SPACE    &amp;    ,    ;    =    ^


Allowed WITHOUT double quotes  :       !    #    $    %    '    (    )    +    -    @    [    ]    _    `   {    }    ~ 

                               :       .       if NOT at END of file name

                               :       SPACE   if NOT at BEGINNING or END of file name
</code></pre>
<hr />
<p dir="auto">You may test the <strong>multi-line</strong> regex above against the text below, pasted in a <strong>new</strong> tab :</p>
<pre><code class="language-diff">============================================= Cas KO : =============================================

""

PRN
aux
NUL
COM1
COM2
com3
COM4
COM5
COM6
COM7
COM8
COM9
COM¹
COM²
COM³
LPT1
LPT2
LPT3
LPT4
LPT5
lpt6
LPT7
LPT8
LPT9
LPT¹
LPT²
LPT³

"PRN"
"aux"
"NUL"

"COM1"
"COM2"
"com3"
"COM4"
"COM5"
"COM6"
"COM7"
"COM8"
"COM9"
"COM¹"
"COM²"
"COM³"

"LPT1"
"LPT2"
"LPT3"
"LPT4"
"LPT5"
"lpt6"
"LPT7"
"LPT8"
"LPT9"
"LPT¹"
"LPT²"
"LPT³"

PRN.
aux.
NUL.
COM1.
COM2.
com3.
COM4.
COM5.
COM6.
COM7.
COM8.
COM9.
COM¹.
COM².
COM³.
LPT1.
LPT2.
LPT3.
LPT4.
LPT5.
lpt6.
LPT7.
LPT8.
LPT9.
LPT¹.
LPT².
LPT³.

"PRN."
"aux."
"NUL."
"COM1."
"COM2."
"com3."
"COM4."
"COM5."
"COM6."
"COM7."
"COM8."
"COM9."
"COM¹."
"COM²."
"COM³."
"LPT1."
"LPT2."
"LPT3."
"LPT4."
"LPT5."
"lpt6."
"LPT7."
"LPT8."
"LPT9."
"LPT¹."
"LPT²."
"LPT³."

PRN.txt
aux.txt
NUL.txt
COM1.txt
COM2.txt
com3.txt
COM4.txt
COM5.txt
COM6.txt
COM7.txt
COM8.txt
COM9.txt
COM¹.txt
COM².txt
COM³.txt
LPT1.txt
LPT2.txt
LPT3.txt
LPT4.txt
LPT5.txt
lpt6.txt
LPT7.txt
LPT8.txt
LPT9.txt
LPT¹.txt
LPT².txt
LPT³.txt

"PRN.txt"
"aux.txt"
"NUL.txt"
"COM1.txt"
"COM2.txt"
"com3.txt"
"COM4.txt"
"COM5.txt"
"COM6.txt"
"COM7.txt"
"COM8.txt"
"COM9.txt"
"COM¹.txt"
"COM².txt"
"COM³.txt"
"LPT1.txt"
"LPT2.txt"
"LPT3.txt"
"LPT4.txt"
"LPT5.txt"
"lpt6.txt"
"LPT7.txt"
"LPT8.txt"
"LPT9.txt"
"LPT¹.txt"
"LPT².txt"
"LPT³.txt"

.
...
..txt..

"."
"..."
"..txt.."

ABCDE			
"ABCDE			"

   abc def ghi . txt      
"   abc def ghi . txt      "

.abc.def.ghi...txt.
".abc.def.ghi...txt."

============================================= Cas OK : =============================================

   xyz
"   xyz"

     .txt
"     .txt"

abc   def   .txt
"abc   def   .txt"

   abc   def   .  txt
"   abc   def   .  txt"

abc.txt

lpt0
COM0

"lpt0"
"COM0"

CONt
tCOM2
tLPT1t
t.NULt

"CONt"
"tCOM2"
"tLPT1t"
"t.NULt"

...xyz...hij..tx
.txt
....txt

"...xyz...hij..tx"
".txt"
"....txt"

a.bcdefghijklmonp
abcdefghijlmnop.z
a.b.c.d.e.f.g.h.i

"a.bcdefghijklmonp"
"abcdefghijlmnop.z"
"a.b.c.d.e.f.g.h.i"

 abc def ghi . txt
" abc def ghi . txt"

.abc.def.ghi...txt
".abc.def.ghi...txt"

!abc!def!ghi!.!txt!
#abc#def#ghi#.#txt#
$abc$def$ghi$.$txt$
%abc%def%ghi%.%txt%
&amp;abc&amp;def&amp;ghi&amp;.&amp;txt&amp;
'abc'def'ghi'.'txt'
(abc(def(ghi(.(txt(
)abc)def)ghi).)txt)
+abc+def+ghi+.+txt+
,abc,def,ghi,.,txt,
-abc-def-ghi-.-txt-
;abc;def;ghi;.;txt;
=abc=def=ghi=.=txt=
@abc@def@ghi@.@txt@
[abc[def[ghi[.[txt[
]abc]def]ghi].]txt]
^abc^def^ghi^.^txt^
_abc_def_ghi_._txt_
`abc`def`ghi`.`txt`
{abc{def{ghi{.{txt{
}abc}def}ghi}.}txt}
~abc~def~ghi~.~txt~

"!abc!def!ghi!.!txt!"
"#abc#def#ghi#.#txt#"
"$abc$def$ghi$.$txt$"
"%abc%def%ghi%.%txt%"
"&amp;abc&amp;def&amp;ghi&amp;.&amp;txt&amp;"
"'abc'def'ghi'.'txt'"
"(abc(def(ghi(.(txt("
")abc)def)ghi).)txt)"
"+abc+def+ghi+.+txt+"
",abc,def,ghi,.,txt,"
"-abc-def-ghi-.-txt-"
";abc;def;ghi;.;txt;"
"=abc=def=ghi=.=txt="
"@abc@def@ghi@.@txt@"
"[abc[def[ghi[.[txt["
"]abc]def]ghi].]txt]"
"^abc^def^ghi^.^txt^"
"_abc_def_ghi_._txt_"
"`abc`def`ghi`.`txt`"
"{abc{def{ghi{.{txt{"
"}abc}def}ghi}.}txt}"
"~abc~def~ghi~.~txt~"
</code></pre>
<p dir="auto">Best Regards,</p>
<p dir="auto">guy038</p>
]]></description><link>https://community.notepad-plus-plus.org/topic/27529/is-a-filename-legal</link><generator>RSS for Node</generator><lastBuildDate>Sun, 10 May 2026 12:18:54 GMT</lastBuildDate><atom:link href="https://community.notepad-plus-plus.org/topic/27529.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 10 May 2026 07:20:12 GMT</pubDate><ttl>60</ttl></channel></rss>