views:

349

answers:

3

Hello to all. Need assistance to do this. Or advice about how to add string to string elements in array?

  1. We have 2 txt files with 100 or more strings in each:

    domain.txt
    domain1
    domain2
    ..
    title.txt
    title1
    tilte2
    ..

  2. and we have:

    string link = < a h ref="http://www.domain.com" target="_blank">title< /a>

  3. After reading files we would have 2 string arrays - we need to replace domain.com with each string from domain.txt and title with each string from title.txt like this:

    < a h ref="http://www.domain1.com" target="_blank">title1< /a>
    < a h ref="http://www.domain2.com" target="_blank">title2< /a>
    ..

  4. Save the result string array into 2 txt files in that way: from 1-50 strings to
    1.txt and from 50-100 to 2.txt file

What is the best way to do this by manipulating strings with strings array elements?

+2  A: 

This is probably the simplest way to read the files:

    string[] domains = File.ReadAllLines("domain.txt");
    string[] titles = File.ReadAllLines("titles.txt");

To make the substitutions you can use string.Format:

    int n = domains.Length;
    string[] results = new string[n];

    for (int i = 0; i < n; ++i)
    {
        results[i] = string.Format(
            @"<a href=""http://{0}"" target=""_blank"">{1}</a>",
            domains[i], titles[i]);
    }

To write the output you can use Linq:

    File.WriteAllLines("file1.txt", results.Take(n / 2).ToArray());
    File.WriteAllLines("file2.txt", results.Skip(n / 2).ToArray());

If your template is a paramter you might want to construct the format string dynamically rather than hardcoding it. Here is an example of how you could do that:

using System;
using System.IO;
using System.Linq;

class Program
{
    static string escapeBraces(string s)
    {
        return s.Replace("{", "{{").Replace("}", "}}");
    }

    static string createFormatString(string template, params string[] parameters)
    {
        template = escapeBraces(template);

        for (int i =0; i < parameters.Length; ++i) {
            template = template.Replace(
                escapeBraces(parameters[i]),
                "{" + i + "}");
        }

        return template;
    }

    static void Main(string[] args)
    {
        string template = @"<a {}href=""http://www.domain.com"" target=""_blank"">title</a>";
        string formatString = createFormatString(template, "www.domain.com", "title");

        string[] domains = File.ReadAllLines("domain.txt");
        string[] titles = File.ReadAllLines("title.txt");

        int n = domains.Length;
        if (titles.Length != n)
            throw new InvalidDataException("There must be the same number domains and titles.");

        string[] results = new string[n];
        for (int i = 0; i < n; ++i)
        {
            results[i] = string.Format(formatString, domains[i], titles[i]);
        }

        File.WriteAllLines("file1.txt", results.Take(n / 2).ToArray());
        File.WriteAllLines("file2.txt", results.Skip(n / 2).ToArray());
    }
}
Mark Byers
This is a way to form a string, but I think the asker wants to modify the existing template, which may not be the best way to proceed.
Hamish Grubijan
Question: does ReadAllInes auto-close and dispose resources as using a "using" + IDisposable would?
Hamish Grubijan
@lpthnc: Yes, `ReadAllLines` uses a `using` block. You can see this in reflector. The implementation is effectively open a `StreamReader` in a `using` block, read the lines one at a time an add them to an `ArrayList`. Then return the `ArrayList` converted to a `string[]` using `ArrayList.ToArray(typeof(string))`.
Jason
@lpthnc: See update at end of comment which addresses your point.
Mark Byers
+2  A: 

This is beautiful using LINQ and some nice methods from File:

string[] domains = File.ReadAllLines(@"C:/domains.txt");
string[] titles = File.ReadAllLines(@"C:/titles.txt");
if(domains.Length != titles.Length) { throw new InvalidOperationException(); }
string link = "<a href=\"http://www.{0}.com\" target=\"_blank\">{1}</a>";
var results = domains.Select((domain, i) => String.Format(link, domain, titles[i]));
File.WriteAllLines("results1.txt", results.Take(results.Length / 2).ToArray());
File.WriteAllLines("results2.txt", results.Skip(results.Length / 2).ToArray());

It isn't clear what you want if there are more than one-hundred domain/title pairs so I split them in half.

Jason
Wow, almost as cool as Python ;)
Hamish Grubijan
It is a lot more elegant in .NET 4.0 when we have Zip.
Mark Byers
@Mark Byers: You are correct sir.
Jason
A: 

Another way is to do it lazily like this:

     static IEnumerable<string> ReadLinesLazily(string file)
 {
  using (var reader = new StreamReader(file))
  {
   string line = null;
   while ((line = reader.ReadLine()) != null)
   {
    yield return line;
   }
  }
 }

 static void Combine()
 {
  const string link = "<a href=\"{0}\">{1}</a>";
  var links = ReadLinesLazily("domains.txt").Zip(ReadLinesLazily("titels.txt"), (d, t) => String.Format(link, d, t))
  // write links here
 }
Dzmitry Huba
It might be worth mentioning that Zip is first included in .NET 4.0.
Mark Byers