VB Script split issue - asp-classic

I use the split function of in VBScript to split the string. Below is the code am using.
Dim inputText
DIM resultArray
inputText = "abc; def; ""xyz;123"""
resultArray = Split(inputText, "; ")
For i = 0 To UBound(resultArray)
resultArray(i) = Replace(resultArray(i), """", "")
resultArray(i) = Replace(resultArray(i), ";", "")
IF i = UBound(resultArray) THEN
Response.Write resultArray(i)
ELSE
Response.Write resultArray(i) & "; "
END IF
Next
If i remove the space after ; in split function it will also split "xyz:123" which i don't want to be.
Either i gave space after ; in split function (Line # 4) or not it shouldn't split the "xyz:123" which comes in double quotes.
Any suggestion how i can achieve this ?
Thanks in advance.

That suspiciously looks like a csv-file. You could try using ADO for this. Microsoft has a fairly extensive (and very useful) article on this: http://msdn.microsoft.com/en-us/library/ms974559.aspx
Since they describe exactly your problem, I think that just might be your solution. :)

Related

Replace the value in asp.net

I want to replace the numeric value in drpFPortofCall.SelectedValue.ToString.
For example, given the string AEJEA~12060 I want the result to be AEJEA. Given the string INNSA~12430 I want the result to be INNSA only. How can I do this?
I tried the following but wasn't able to get through.
Dim frmport As String = drpFPortofCall.SelectedValue.ToString
frmport = frmport.Replace("~", "")
Easy and Simple
Using IndexOf you will replace the rest
Dim frmport As String = drpFPortofCall.SelectedValue.ToString()
Dim value as String = frmport.Substring(0, frmport.IndexOf("~"))
You can use regex to extract everything until the "~".
Here is an example. And a fiddle.
Dim foo = "AEJEA~12060"
Dim match = Regex.Match(foo,".+?(?=~)")
Dim x = match.Value
Console.WriteLine("x = " & x)
Edit: you will need this import:
Imports System.Text.RegularExpressions
First of all, I'm pretty sure drpFPortofCall.SelectedValue is already a string (What you have might not be a ListControl directly, but it almost certainly inherits this property from it). That is, further calling .ToString() from there is silly at best and wasteful at worst.
Moving on from there, it seems like you want everything up to the ~. One option looks like this:
Dim frmport As String = drpFPortofCall.SelectedValue.Split("~"c)(0)
But that might be slower. With a little more code we could do it like this, which might be very slightly faster:
Dim endIndex As Integer = drpFPortofCall.SelectedValue.IndexOf("~"c)
Dim frmPort As String = drpFPortofCall.SelectedValue.SubString(0, endIndex)
... but you won't notice the difference unless you need to run this on 10s of thousands of inputs.
Finally, the two samples we have are strikingly similar in structure, down to the number of characters in each spot. If you can be sure that all of your data follows this format exactly, we can do even better:
Dim frmPort As String = drpFPortofCall.SelectedValue.SubString(0, 5)

string.split()(1) removes first character

I am running into an issue when i split a string on "_Pub" and get the back half of the string it removes the first character and I don't understand why or how to fix it unless i add the character back in
strFilePath = "/C:/Dev/Edge/_Publications/Ann Report/2013-2016/2016 Edge.pdf"
Dim relPath = strFilepath.Split("_Publications")(1)
lb.CommandArgument = relPath
returns Publications\Ann Report\2013-2016\2016 Edge.pdf
What you have as a delimiter is not a string array "string()" but a regular string. You need a string array to use a string as a delimiter. otherwise it takes the first char of your string.
https://msdn.microsoft.com/en-us/library/tabh47cf(v=vs.110).aspx
try this
Dim relPath = strFilepath.Split(new string() {"_Publications"}, StringSplitOptions.RemoveEmptyEntries)(1)
It appears that you want to get the part of the path starting at some directory. Splitting the path might not be such a good idea: imagine if there was a file "My_Publications_2017.pdf" in a directory "C:\Dev\Edge\_Publications". The split as you intended in the question would give the array of strings {"C:\Dev\Edge\", "\My", "_2017.pdf"}. As has been pointed out elsewhere, the String.Split you used doesn't do that anyway.
A more robust way would be to find where the starting directory's name is in the full path and get the substring of the path starting with it, e.g.:
Function GetRelativePath(fullPath As String, startingDirectory As String) As String
' Fix some errors in how the fullPath might be supplied:
Dim tidiedPath = Path.GetFullPath(fullPath.TrimStart("/".ToCharArray()))
Dim sep = Path.DirectorySeparatorChar
Dim pathRoot = sep & startingDirectory.Trim(New Char() {sep}) & sep
Dim i = tidiedPath.IndexOf(pathRoot)
If i < 0 Then
Throw New DirectoryNotFoundException($"Cannot find {pathRoot} in {fullPath}.")
End If
' There will be a DirectorySeparatorChar at the start - do not include it
Return tidiedPath.Substring(i + 1)
End Function
So,
Dim s = "/C:/Dev/Edge/_Publications/Ann Report/2013-2016/2016 Edge.pdf"
Console.WriteLine(GetRelativePath(s, "_Publications"))
Console.WriteLine(GetRelativePath(s, "\Ann Report"))
outputs:
_Publications\Ann Report\2013-2016\2016 Edge.pdf
Ann Report\2013-2016\2016 Edge.pdf
Guessing that you might have several malformed paths starting with a "/" and using "/" as the directory separator character instead of "\", I put some code in to mitigate those problems.
The Split() function is supposed to exclude the entire delimiter from the result. Could you re-check & confirm your input and output strings?

Escaping apostrophe/single quote in parameterized sql in asp

I'm new to parametrized SQL. I've got a query in an .asp page that's getting one or more client names from a form. These are held in an array called clientArr and then passed through to SQL server as parameters. I'm escaping the ' as '' but this doesn't appear to be working. If I run the query with a client name like McDonald's, it returns no results.
clientArr(y) = Replace(clientArr(y),"'","''"
...
if qsClient > "" Then
dim booComma
booComma = false
if mySQLwhere > "" Then
mySQLwhere = mySQLwhere& " AND "
End if
mySQLwhere = mySQLwhere & " (p.client IN ( "
for y = 0 to Ubound(clientArr)
if booComma = true Then
mySQLwhere = mySQLwhere & ","
end if
mySQLwhere = mySQLwhere & "?"
booComma = true
Next
mySQLwhere = mySQLwhere & ")) "
end if
...
if qsClient > "" Then
for y = 0 to Ubound(clientArr)
Response.write clientArr(y)
set prm = cmd.CreateParameter("#prm", 129, 1, 50, clientArr(y))
cmd.Parameters.Append prm
next
end if
If I run the query directly or create it by concatenating strings rather then use parameters, it works fine. It also works fine is I use a client name without an apostrophe.
Any help would be much appreciated. Happy to provide more info if I can.
Thanks,
Tim
After working on this for far too long, it just hit me. Passing the parameter straight through like this means that I don't need to escape it at all. If I remove that replace statement, it works just fine keeping the single quote. I was definitely over-thinking this.

String.Replace not replacing vbCrlf

I am trying to replace all the occurrences of "\n" in the Text property of an ASP.NET TextBox with <br /> using String.Repalce function, but it doesn't seem to work:
taEmailText.Text.Replace("\n", "<br />")
As a solution I am using Regex.Replace:
New Regex("\n").Replace(taEmailText.Text, "<br />")
My question is why String.Replace can't find "\n" for me, even though this solution has been proposed on many sites and it has worked for many people.
Thanks,
In .NET string objects are immutable, so String.Replace returns a new string with the replacement. You need to assign the result:
taEmailText.Text = taEmailText.Text.Replace("\n", "<br />")
Also, rather than creating a new Regex object—when you do need a regular expression—then there are static methods available:
result = Regex.Replace(input, pattern, replacement)
Edit (based on comment):
Just tested this:
Sub Main()
Dim result As String = "One\nTwo".Replace("\n", "<br />")
Console.WriteLine(result)
End Sub
and the result is:
One<br />Two
The problem is the result of the method call is immediated forgotten. You should read MSDN documentation a bit more carefully:
Returns a new string in which all occurrences…
Hence do:
taEmailText.Text = taEmailText.Text.Replace("\n", "<br />")
Replace does not change the content of the input string. It returns newly created string.
You might want to replace both \r and \n or use Environment.NewLine constant.
var replacedText = TextBox1.Text.Replace(Environment.NewLine, "<br />");

How do I best generate a CSV (comma-delimited text file) for download with ASP.NET?

This is what I've got. It works. But, is there a simpler or better way?
One an ASPX page, I've got the download link...
<asp:HyperLink ID="HyperLinkDownload" runat="server" NavigateUrl="~/Download.aspx">Download as CSV file</asp:HyperLink>
And then I've got the Download.aspx.vb Code Behind...
Public Partial Class Download
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'set header
Response.Clear()
Response.ContentType = "text/csv"
Dim FileName As String = "books.csv"
Response.AppendHeader("Content-Disposition", "attachment;filename=" + FileName)
'generate file content
Dim db As New bookDevelopmentDataContext
Dim Allbooks = From b In db.books _
Order By b.Added _
Select b
Dim CsvFile As New StringBuilder
CsvFile.AppendLine(CsvHeader())
For Each b As Book In Allbooks
CsvFile.AppendLine(bookString(b))
Next
'write the file
Response.Write(CsvFile.ToString)
Response.End()
End Sub
Function CsvHeader() As String
Dim CsvLine As New StringBuilder
CsvLine.Append("Published,")
CsvLine.Append("Title,")
CsvLine.Append("Author,")
CsvLine.Append("Price")
Return CsvLine.ToString
End Function
Function bookString(ByVal b As Book) As String
Dim CsvLine As New StringBuilder
CsvLine.Append(b.Published.ToShortDateString + ",")
CsvLine.Append(b.Title.Replace(",", "") + ",")
CsvLine.Append(b.Author.Replace(",", "") + ",")
CsvLine.Append(Format(b.Price, "c").Replace(",", ""))
Return CsvLine.ToString
End Function
End Class
CSV formatting has some gotchas. Have you asked yourself these questions:
Does any of my data have embedded commas?
Does any of my data have embedded double-quotes?
Does any of my data have have newlines?
Do I need to support Unicode strings?
I see several problems in your code above. The comma thing first of all... you are stripping commas:
CsvLine.Append(Format(b.Price, "c").Replace(",", ""))
Why? In CSV, you should be surrounding anything which has commas with quotes:
CsvLine.Append(String.Format("\"{0:c}\"", b.Price))
(or something like that... my VB is not very good). If you're not sure if there are commas, but put quotes around it. If there are quotes in the string, you need to escape them by doubling them. " becomes "".
b.Title.Replace("\"", "\"\"")
Then surround this by quotes if you want. If there are newlines in your string, you need to surround the string with quotes... yes, literal newlines are allowed in CSV files. It looks weird to humans, but it's all good.
A good CSV writer requires some thought. A good CSV reader (parser) is just plain hard (and no, regex not good enough for parsing CSV... it will only get you about 95% of the way there).
And then there is Unicode... or more generally I18N (Internationalization) issues. For example, you are stripping commas out of a formatted price. But that's assuming the price is formatted as you expect it in the US. In France, the number formatting is reversed (periods used instead of commas, and vice versa). Bottom line, use culture-agnostic formatting wherever possible.
While the issue here is generating CSV, inevitably you will need to parse CSV. In .NET, the best parser I have found (for free) is Fast CSV Reader on CodeProject. I've actually used it in production code and it is really really fast, and very easy to use!
I pass all my CSV data through a function like this:
Function PrepForCSV(ByVal value As String) As String
return String.Format("""{0}""", Value.Replace("""", """"""))
End Function
Also, if you're not serving up html you probably want an http handler (.ashx file) rather than a full web page. If you create a new handler in Visual Studio, odds are you could just copy past your existing code into the main method and it will just work, with a small performance boost for your efforts.
You can create the equivalent of bookString() in the query itself. Here is what I think would be a simpler way.
protected void Page_Load(object sender, EventArgs e)
{
using (var db = new bookDevelopmentDataContext())
{
string fileName = "book.csv";
var q = from b in db.books
select string.Format("{0:d},\"{1}\",\"{2}\",{3:F2}", b.Published, b.Title.Replace("\"", "\"\""), b.Author.Replace("\"", "\"\""), t.price);
string outstring = string.Join(",", q.ToArray());
Response.Clear();
Response.ClearHeaders();
Response.ContentType = "text/csv";
Response.AppendHeader("Content-Disposition", string.Format("attachment;filename={0}", fileName));
Response.Write("Published,Title,Author,Price," + outstring);
Response.End();
}
}
If you want a colon delimited value converter then there is a 3rd party open source called FileHelpers. I'm not sure about what open-source license it is under, but it has helped me quite a lot.
In addition to what Simon said, you may want to read the CSV how-to guide and make sure your output doesn't run across any of the gotchas.
To clarify something Simon said:
Then surround this by quotes if you want
Fields that contain doubled up double quotes ("") will need to be completely surrounded with double quotes. There shouldn't be any harm in just wrapping all fields with double quotes, unless you specifically want the parser to strip out leading and trailing whitespace (instead of trimming it yourself).
There's a lot of overhead associated with the Page class. Since you're just spitting out a CSV file and have no need for postback, server controls, caching, or the rest of it, you should make this into a handler with an .ashx extension. See here.
I use the following method when building a CSV file from a DataTable. ControllerContext is just the reponse stream object where the file is written to. For you it is just going to be the Response object.
public override void ExecuteResult(ControllerContext context)
{
StringBuilder csv = new StringBuilder(10 * Table.Rows.Count * Table.Columns.Count);
for (int c = 0; c < Table.Columns.Count; c++)
{
if (c > 0)
csv.Append(",");
DataColumn dc = Table.Columns[c];
string columnTitleCleaned = CleanCSVString(dc.ColumnName);
csv.Append(columnTitleCleaned);
}
csv.Append(Environment.NewLine);
foreach (DataRow dr in Table.Rows)
{
StringBuilder csvRow = new StringBuilder();
for(int c = 0; c < Table.Columns.Count; c++)
{
if(c != 0)
csvRow.Append(",");
object columnValue = dr[c];
if (columnValue == null)
csvRow.Append("");
else
{
string columnStringValue = columnValue.ToString();
string cleanedColumnValue = CleanCSVString(columnStringValue);
if (columnValue.GetType() == typeof(string) && !columnStringValue.Contains(","))
{
cleanedColumnValue = "=" + cleanedColumnValue; // Prevents a number stored in a string from being shown as 8888E+24 in Excel. Example use is the AccountNum field in CI that looks like a number but is really a string.
}
csvRow.Append(cleanedColumnValue);
}
}
csv.AppendLine(csvRow.ToString());
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = "text/csv";
response.AppendHeader("Content-Disposition", "attachment;filename=" + this.FileName);
response.Write(csv.ToString());
}
protected string CleanCSVString(string input)
{
string output = "\"" + input.Replace("\"", "\"\"").Replace("\r\n", " ").Replace("\r", " ").Replace("\n", "") + "\"";
return output;
}
Looking mostly good except in your function "BookString()" you should pass all those strings through a small function like this first:
Private Function formatForCSV(stringToProcess As String) As String
If stringToProcess.Contains("""") Or stringToProcess.Contains(",") Then
stringToProcess = String.Format("""{0}""", stringToProcess.Replace("""", """"""))
End If
Return stringToProcess
End Function
'So, lines like this:
CsvLine.Append(b.Title.Replace(",", "") + ",")
'would be lines like this instead:
CsvLine.Append(formatForCSV(b.Title)) + ",")
The function will format your strings well for CSV. It replaces quotes with double quotes and add quotes around the string if there are either quotes or commas in the string.
Note that it doesn't account for newlines, but can only safely guarantee good CSV output for those strings that you know are free of newlines (inputs from simple one-line text forms, etc.).

Resources