{"id":70083,"date":"2005-04-06T15:57:00","date_gmt":"2005-04-06T15:57:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2005\/04\/06\/how-can-i-convert-a-comma-separated-values-file-to-a-tab-separated-values-file\/"},"modified":"2005-04-06T15:57:00","modified_gmt":"2005-04-06T15:57:00","slug":"how-can-i-convert-a-comma-separated-values-file-to-a-tab-separated-values-file","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-can-i-convert-a-comma-separated-values-file-to-a-tab-separated-values-file\/","title":{"rendered":"How Can I Convert a Comma-Separated Values File to a Tab-Separated Values File?"},"content":{"rendered":"<p><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" height=\"34\" alt=\"Hey, Scripting Guy! Question\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"> \n<P>Hey, Scripting Guy! How can I convert a comma-separated values file to a tab-separated values file?<BR><BR>&#8212; RV<\/P><IMG height=\"5\" alt=\"Spacer\" src=\"https:\/\/devblogs.microsoft.com\/scripting\/wp-content\/uploads\/sites\/29\/2019\/05\/spacer.gif\" width=\"5\" border=\"0\"><IMG class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" height=\"34\" alt=\"Hey, Scripting Guy! Answer\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" align=\"left\" border=\"0\"><A href=\"http:\/\/go.microsoft.com\/fwlink\/?linkid=68779&amp;clcid=0x409\"><IMG class=\"farGraphic\" title=\"Script Center\" height=\"288\" alt=\"Script Center\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/ad.jpg\" width=\"120\" align=\"right\" border=\"0\"><\/A> \n<P>Hey, RV. Depending on the nature of your comma-separated values (CSV) file this is either very easy or a little bit tricky. Let\u2019s follow the Scripting Guys Philosophy of Life and look at the easy one first.<\/P>\n<TABLE class=\"dataTable\" id=\"EYC\" cellSpacing=\"0\" cellPadding=\"0\">\n<THEAD><\/THEAD>\n<TBODY>\n<TR class=\"record\" vAlign=\"top\">\n<TD class=\"\">\n<P class=\"lastInCell\"><B>Note<\/B>. Of course, in our <I>real<\/I> Philosophy of Life we\u2019d take the easy one first and then hope that there wouldn\u2019t be time to do the hard one as well. Today, however, we\u2019ll make an exception and tackle both the easy one and the hard one.<\/P><\/TD><\/TR><\/TBODY><\/TABLE>\n<DIV class=\"dataTableBottomMargin\"><\/DIV>\n<P>Let\u2019s assume we have a very simple CSV file, one that looks like this:<\/P><PRE class=\"codeSample\">a,b,c,d,e,f\ng,h,i,j,k,l\nm,n,o,p,q,r\ns,t,u,v,w,x\ny,z\n<\/PRE>\n<P>How can we convert this to a tab-separated values file (TSV)? Like we said, this is pretty easy. We\u2019ll begin by opening the file and reading the entire contents into a variable. Once the file contents are in memory we\u2019ll replace all the commas with tabs and then re-save the file. Just like magic we\u2019ll have turned a CSV file into a TSV file. Here\u2019s the code that does the trick:<\/P><PRE class=\"codeSample\">Const ForReading = 1\nConst ForWriting = 2<\/p>\n<p>Set objFSO = CreateObject(&#8220;Scripting.FileSystemObject&#8221;)<\/p>\n<p>Set objFile = objFSO.OpenTextFile(&#8220;C:\\scripts\\test.txt&#8221;, ForReading)\nDo Until objFile.AtEndOfStream\n    strLine = objFile.ReadLine\n    strLine = Replace(strLine, &#8220;,&#8221;, vbTab)\n    strNewText = strNewText &amp; strLine &amp; vbCrLF\nLoop<\/p>\n<p>objFile.Close<\/p>\n<p>Set objFile = objFSO.OpenTextFile(&#8220;C:\\scripts\\test.txt&#8221;, ForWriting)\nobjFile.WriteLine strNewText<\/p>\n<p>objFile.Close\n<\/PRE>\n<P>We begin by defining two constants &#8211; ForReading and ForWriting &#8211; that we use when opening and then re-opening our file (C:\\Scripts\\Test.txt). And, yes, we said re-opening: when using the <B>FileSystemObject<\/B> to work with text files you can open a file for reading <I>or<\/I> you can open a file for writing; unfortunately, you can\u2019t do both at the same time. Because of that we\u2019ll need to open the file, read the contents into memory, close the file, and then re-open that same file for writing in order to save the modified data.<\/P>\n<P>After defining our constants we create an instance of the FileSystemObject and use the <B>OpenTextFile<\/B> method to open the file for reading. We then create a Do Loop in which we\u2019ll read in the existing CSV file and then construct our new TSV file.<\/P>\n<P>How do we do that? We begin by using the <B>ReadLine<\/B> method to read the first line of the file and store it in a variable named strLine. Next we use the VBScript <B>Replace<\/B> method to replace all the commas in the variable with tab characters; that\u2019s what happens here:<\/P><PRE class=\"codeSample\">strLine = Replace(strLine, &#8220;,&#8221;, vbTab)\n<\/PRE>\n<P>Note that we use the VBScript constant <B>vbTab<\/B> to indicate the tab character; had we used something like <B>\u201ctab\u201d<\/B> we would have replaced all the commas with the word <I>tab<\/I>. Not exactly what we had in mind. Likewise, don\u2019t try typing a set of double quotes, setting the cursor inside those double quotes and pressing the TAB key (\u201c \u201c). That just won\u2019t work.<\/P>\n<P>After we replace the commas with tabs we can start putting together our revised file. In this line of code we assign the variable strNewText the current value of strNewText (which, the first time through the loop, will be nothing) <I>plus<\/I> the new, tab-delimited strLine <I>plus<\/I> a carriage-return linefeed (vbCrLf): <\/P><PRE class=\"codeSample\">strNewText = strNewText &amp; strLine &amp; vbCrLF\n<\/PRE>\n<P>The first time through the loop strNewText will look like this, with tabs replacing the commas:<\/P><PRE class=\"codeSample\">a     b     c     d     e     f\n<\/PRE>\n<P>We then loop around and repeat the process with line 2. By the time we\u2019ve finished reading in all the lines of the file the variable strNewText will hold this value:<\/P><PRE class=\"codeSample\">a     b     c     d     e     f\ng     h     i     j     k     l\nm     n     o     p     q     r\ns     t     u     v     w     x\ny     z\n<\/PRE>\n<P>As you can see, we\u2019ve removed all the commas and replaced them with tabs. All we have to do now is close the file and then re-open it for writing. With the file re-opened we can use the <B>WriteLine<\/B> method to replace the existing contents of the file with the value of strNewText. And that\u2019s it: our CSV file is now a TSV file. And we did it all PDQ ASAP. <\/P>\n<P>See, that <I>was<\/I> pretty easy, wasn\u2019t it? Now, what about that harder scenario? Well, suppose we have a CSV file that looks like this:<\/P><PRE class=\"codeSample\">&#8220;a&#8221;,&#8221;b,c,d,e&#8221;,&#8221;f&#8221;\n&#8220;g&#8221;,&#8221;h&#8221;,&#8221;i&#8221;\n&#8220;j&#8221;,&#8221;k&#8221;,&#8221;l,m,n,o,p,q,r,s,t,u,v,w,x,y,z&#8221;\n<\/PRE>\n<P>This is still a CSV file; the difference is that individual items are enclosed in double quote marks. That\u2019s because some of the items include commas themselves. For example, the first line in the file is actually composed of these three items:<\/P><PRE class=\"codeSample\">a     b,c,d,e     f\n<\/PRE>\n<P>Why do we care about that? Well, suppose we use our previous script and simply replace all the commas with tabs. If we do that, our first line will be divvied up like this:<\/P><PRE class=\"codeSample\">&#8220;a&#8221;     &#8220;b     c     d     e&#8221;     &#8220;f&#8221;\n<\/PRE>\n<P>Oops; that\u2019s not even close to being right. The problem (aside from the double quotes) lies with the commas found inside the double quote marks; those commas should <I>not<\/I> be converted to tabs. How are we going to deal with <I>that<\/I>?<\/P>\n<P>Well, to be honest, the best way to deal with this issue would be to use regular expressions. However, explaining how regular expressions work lies way beyond the scope of this column; to learn more about that we encourage you to view the <A href=\"http:\/\/go.microsoft.com\/fwlink\/?LinkId=44007\" target=\"_blank\"><B>Scripting Guys webcast<\/B><\/A> on the subject. In the meantime, we\u2019ll show you a solution that, while not 100% foolproof, should work in most situations:<\/P><PRE class=\"codeSample\">Const ForReading = 1\nConst ForWriting = 2<\/p>\n<p>Set objFSO = CreateObject(&#8220;Scripting.FileSystemObject&#8221;)<\/p>\n<p>Set objFile = objFSO.OpenTextFile(&#8220;C:\\scripts\\test.txt&#8221;, ForReading)\nDo Until objFile.AtEndOfStream\n    strLine = objFile.ReadLine\n    strReplacer = Chr(34) &amp; &#8220;,&#8221; &amp; Chr(34)\n    strLine = Replace(strLine, strReplacer, vbTab)\n    strLine = Replace(strLine, chr(34), &#8220;&#8221;)\n    strNewText = strNewText &amp; strLine &amp; vbCrLF\nLoop<\/p>\n<p>objFile.Close<\/p>\n<p>Set objFile = objFSO.OpenTextFile(&#8220;C:\\scripts\\test.txt&#8221;, ForWriting)\nobjFile.WriteLine strNewText<\/p>\n<p>objFile.Close\n<\/PRE>\n<P>The difference between this script and the first one we showed you occurs when we go about replacing commas in a line. We now do that using these three lines of code:<\/P><PRE class=\"codeSample\">strReplacer = Chr(34) &amp; &#8220;,&#8221; &amp; Chr(34)\nstrLine = Replace(strLine, strReplacer, vbTab)\nstrLine = Replace(strLine, chr(34), &#8220;&#8221;)\n<\/PRE>\n<P>In the first line we\u2019re assigning the value <B>Chr(34) &amp; &#8220;,&#8221; &amp; Chr(34)<\/B> to a variable named strReplacer; that means strReplacer will now be equal to this:<\/P><PRE class=\"codeSample\">&#8220;,&#8221;\n<\/PRE>\n<P>What was the point of that? Well, as we\u2019ve already seen, we can\u2019t search for and replace <I>all<\/I> commas. Therefore, what we\u2019re going to do in line 2 is search for double quotes followed by a comma followed by another set of double quotes. Sounds crazy but if you take a look at line 1 in our text file you\u2019ll see that this is actually the pattern used to separate items:<\/P><PRE class=\"codeSample\">&#8220;a&#8221;,&#8221;b,c,d,e&#8221;,&#8221;f&#8221;\n<\/PRE>\n<P>In other words, replacing all instances of <B>\u201c,\u201d <\/B>will yield this:<\/P><PRE class=\"codeSample\">&#8220;a     b,c,d,e     f&#8221;\n<\/PRE>\n<P>As you can see, that\u2019s pretty close to what we want; we just need to do something about those extraneous double quotes. That\u2019s what we do with our third line of code, which replaces any remaining double quote marks with nothing:<\/P><PRE class=\"codeSample\">strLine = Replace(strLine, chr(34), &#8220;&#8221;)\n<\/PRE>\n<P>The net result? Just what the doctor ordered:<\/P><PRE class=\"codeSample\">a     b,c,d,e     f\n<\/PRE>\n<P>Again, not a foolproof method, but it will work in most cases. If you find that it <I>doesn\u2019t<\/I> work in your case, then view the <A href=\"http:\/\/go.microsoft.com\/fwlink\/?LinkId=44007\" target=\"_blank\"><B>regular expressions webcast<\/B><\/A>.<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hey, Scripting Guy! How can I convert a comma-separated values file to a tab-separated values file?&#8212; RV Hey, RV. Depending on the nature of your comma-separated values (CSV) file this is either very easy or a little bit tricky. Let\u2019s follow the Scripting Guys Philosophy of Life and look at the easy one first. Note. [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[169,3,4,5],"class_list":["post-70083","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-csv-and-other-delimited-files","tag-scripting-guy","tag-scripting-techniques","tag-vbscript"],"acf":[],"blog_post_summary":"<p>Hey, Scripting Guy! How can I convert a comma-separated values file to a tab-separated values file?&#8212; RV Hey, RV. Depending on the nature of your comma-separated values (CSV) file this is either very easy or a little bit tricky. Let\u2019s follow the Scripting Guys Philosophy of Life and look at the easy one first. Note. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/70083","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=70083"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/70083\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=70083"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=70083"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=70083"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}