1 Востаннє редагувалося funivan (19.03.2013 10:57:26)

Тема: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Вирішив створити тему під кожну задачу. Можливо в майбутньому ці теми адмін перенесе у одну гілку і все буде красиво. Поки що пропоную наступний принцип:
1. Пишемо умову задачі.
2. Пишемо розв'язок на 1ній з мов.
3. Обговорюємо.
4. Чекаємо коли користувачі напишуть на інших мовах варіант розв'язання задачі і додаємо його в головне повідомлення теми.
5. В головному повідомлені теми ставимо посилання на зв'язані теми.

Задача:
Є файл з описом будинків. Потрібно його прочитати і вивести назву вулиці і назву будинку окремо. Тобто дані мають бути структуровані. Дані розбиті табуляцією. Якщо в рядку більше 1ї табуляції (табуляції у кінці і спочатку не враховуємо) він не підходить, значить пропускаємо його. В даній задачі стараємось показати простоту мови і її синтаксис.

вул. Сергія Єфремова    1/2
вул. 100-Р.Червоного Хреста    1
вул. 100-Р.Червоного Хреста    2
вул. 100-Р.Червоного Хреста    3
вул. 100-Р.Червоного Хреста    2в
вул. 2000-Ліття Різдва Христового    4
вул. 24 Серпня    1

Задачу придумав bunyk, я трохи перефразував ;)


Реалізація на PHP:

<?php
  # author @funivan
  $data = file_get_contents('buildings.txt'); # зчитуємо файл
  $lines = explode(PHP_EOL, $data);  # розбиваємо файл по закінченню рядка

  foreach ($lines as $line) {
    $houseInfo = explode("\t", trim($line)); # розбиваємо рядок по табах
    if (count($houseInfo) == 2) {
      # фільтруємо і виводимо дані
      echo "Street: " . $houseInfo[0] . "\nHouse : " . $houseInfo[1] . "\n\n";
    }
  }

Результат:

Прихований текст

Street: вул. Сергія Єфремова
House : 1/2

Street: вул. 100-Р.Червоного Хреста
House : 1

Street: вул. 100-Р.Червоного Хреста
House : 2

Street: вул. 100-Р.Червоного Хреста
House : 3

Street: вул. 100-Р.Червоного Хреста
House : 2в

Street: вул. 24 Серпня
House : 1



Реалізація на Python:

    # author @bunyk
    with open('buildings.txt') as f:
    for line in f:
      split = line.strip().split('\t') # Викинути зайве по краях і розділити через табуляцію.
      if len(split) == 2: # деякі рядки містять помилки
         building, street = split
         print(building, street)

Результат:

Прихований текст
скоро буде


Реалізація на Ruby:

IO.foreach "t.html" do |line|
    lines = line.strip.split("\t")
    puts (lines.size == 2) ? "Street: #{line[0]}\nHouse: #{line[1]}\n\n" : ""
end
Прихований текст

    Street: вул. Сергія Єфремова
    House: 1/2
     
    Street: вул. 100-Р.Червоного Хреста
    House: 1
     
    Street: вул. 100-Р.Червоного Хреста
    House: 2
     
    Street: вул. 100-Р.Червоного Хреста
    House: 3
     
    Street: вул. 100-Р.Червоного Хреста
    House: 2в
     
    Street: вул. 2000-Ліття Різдва Христового
    House: 4
     
    Street: вул. 24 Серпня
    House: 1



Реалізація на C++:

#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
using namespace std;

void showFile(const char* /*file*/);
int main(int argc, char* argv[])
{
    if(argc>2)
        showFile(argv[1]);
    return 0;
}

#define trim(s)    { while(s[0]=='\t')    s=s.substr(1);    \
                          while(s[s.length()-1]=='\t')    s=s.substr(0,s.length()-1);}
void showFile(const char* file)
{
    ifstream f(file);
    string content( (std::istreambuf_iterator<char>(f)), (std::istreambuf_iterator<char>()) ),
           line, token;
    f.close();
    istringstream fileStream(content);
    vector<string> rowTokens;
    while(getline(fileStream,line))
    {
        trim(line);
        istringstream stream(line);
        while(getline(stream,token, '\t'))
            rowTokens.push_back(token);
        if(rowTokens.size() == 2) /*validation rule*/
            cout<<rowTokens[0].c_str()<<" ---> "<<rowTokens[1].c_str()<<endl;
        rowTokens.clear();
    }
}

Результат:

Прихований текст
http://s7.postimage.org/h3g74vjrv/res.jpg

Реалізація на JAVA:

public class ParseFile {
    public static void main(String[] args) {
        try (java.util.Scanner scanner = new java.util.Scanner(new java.io.File(args[0]))) {
            while (scanner.hasNextLine()) {
                String[] str = scanner.nextLine().replaceAll("^\t+|\t$+", "").split("\t");
                if (str.length == 2) {
                    System.out.printf("%s ---> %s\n", str[0], str[1]);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

Результат:

Прихований текст

    вул. Сергія Єфремова ---> 1/2
    вул. 100-Р.Червоного Хреста ---> 1
    вул. 100-Р.Червоного Хреста ---> 2
    вул. 100-Р.Червоного Хреста ---> 3
    вул. 100-Р.Червоного Хреста ---> 2в
    вул. 2000-Ліття Різдва Христового ---> 4
    вул. 24 Серпня ---> 1





Реалізація на C#:

using System;
using System.IO; 

public class HelloWorld
{
    static public void Main ()
    {
        try
        {
            using (StreamReader reader = new StreamReader("t.html"))
            {
                String line;
                while ((line = reader.ReadLine()) != null)
                {
                    String[] items = line.Trim().Split(new Char[] {'\t'});
                    if (items.Length == 2)
                    {
                        Console.WriteLine("Street: " + items[0]);
                        Console.WriteLine("House: " + items[1]);
                        Console.WriteLine();
                    }
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
 
}

Результат:

Прихований текст

Street: вул. Сергія Єфремова
House: 1/2

Street: вул. 100-Р.Червоного Хреста
House: 1

Street: вул. 100-Р.Червоного Хреста
House: 2

Street: вул. 100-Р.Червоного Хреста
House: 3

Street: вул. 100-Р.Червоного Хреста
House: 2в

Street: вул. 2000-Ліття Різдва Христового
House: 4

Street: вул. 24 Серпня
House: 1




Реалізація на BASH:

#!/bin/bash
mIFS="$IFS"
IFS=$'\n'
while read line
do
    str=$line
    str="${str#"${str%%[![:space:]]*}"}" #//не зовсім, але ...
    str="${str%"${str##*[![:space:]]}"}" #//не зовсім, але ...

    IFS=`/bin/echo -ne "\t"` read -a array <<< "$str"
    if [ ${#array[*]} -eq  2 ]
    then
        printf '%s ---> %s ' "${array[0]}" "${array[1]}"; printf '\n'
    fi
done <$1|iconv -f CP1251 -t UTF-8
IFS="$mIFS"

Результат роботи

Прихований текст

> ./ParseFile.sh 01.txt
вул. Сергія Єфремова ---> 1/2
вул. 100-Р.Червоного Хреста ---> 1
вул. 100-Р.Червоного Хреста ---> 2
вул. 100-Р.Червоного Хреста ---> 3
вул. 100-Р.Червоного Хреста ---> 2в
вул. 2000-Ліття Різдва Христового ---> 4

> ./ParseFile.sh file.txt
Simple street ---> 222
street with forward tabs ---> 111
street with tabs at the end ---> 222




Реалізація на SQL+Postgresql:

> psql -a -t -d postgres -p 5432 -h 127.0.0.1 -c "\
select str[1]||' ---> '||str[2]
  from (select string_to_array( regexp_replace(line, '(^[\s\t\n\r]+|[\s\t\n\r]+$)', '', 'g'), e'\t') as str\
          from unnest(string_to_array(convert_from(pg_read_binary_file('./01.txt'), 'win1251'), e'\n')) as foo (line)) foo\
 where array_length(str, 1) = 2"

Результат:

Прихований текст

 вул. Сергія Єфремова ---> 1/2
 вул. 100-Р.Червоного Хреста ---> 1
 вул. 100-Р.Червоного Хреста ---> 2
 вул. 100-Р.Червоного Хреста ---> 3
 вул. 100-Р.Червоного Хреста ---> 2в
 вул. 2000-Ліття Різдва Христового ---> 4
 вул. 24 Серпня ---> 1


Реалізація на PLPGSQL+Postgresql

DO $$
DECLARE
  loidTxt oid;
  lfdTxt integer;
  fileTxt bytea;
  sizeTxt integer;
  line record;
  rec record;
BEGIN
        loidTxt := lo_import('./01.txt');
        lfdTxt := lo_open(loidTxt, X'20000'::int);
        sizeTxt       := lo_lseek(lfdTxt,0,2);
        perform lo_lseek(lfdTxt,0,0);
        fileTxt       := loread(lfdTxt,sizeTxt);
        --raise NOTICE '%', convert_from(filetxt, 'win1251');
        for line in SELECT UNNEST(string_to_array(convert_from(filetxt, 'win1251'), E'\n')) AS l
        LOOP
           for rec in select string_to_array( regexp_replace(line.l, '(^[\s\t\n\r]+|[\s\t\n\r]+$)', '', 'g'), E'\t') AS str
           LOOP
                IF array_length(rec.str,1)=2
                THEN
                        raise NOTICE '% ---> %', rec.str[1], rec.str[2];
                END IF;
           END LOOP;
        END LOOP;

        perform lo_close(lfdTxt);
        perform lo_unlink(loidTxt);

END $$;

Результат

Прихований текст

NOTICE:  вул. Сергія Єфремова ---> 1/2
NOTICE:  вул. 100-Р.Червоного Хреста ---> 1
NOTICE:  вул. 100-Р.Червоного Хреста ---> 2
NOTICE:  вул. 100-Р.Червоного Хреста ---> 3
NOTICE:  вул. 100-Р.Червоного Хреста ---> 2в
NOTICE:  вул. 2000-Ліття Різдва Христового ---> 4
NOTICE:  вул. 24 Серпня ---> 1





З чого все починалось:
http://replace.org.ua/topic/995/

Подякували: Replace, bunyk, Bartash3

2

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Лише  PHP, Python та Ruby?

3

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Давайте тоді уже приклади робити різними мовами, а не тільки трьома у назві теми. :)

I belong to the Dead Generation.

4 Востаннє редагувалося funivan (17.03.2013 11:30:20)

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Bartash написав:

Давайте тоді уже приклади робити різними мовами, а не тільки трьома у назві теми. :)

давайте =) головне знайти народ хто буде кодити на якій мові ))

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Я за Bash :)

6

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

funivan написав:

давайте =) головне знайти народ хто буде кодити на якій мові ))

Предствавлю рішення на класичному С++ сьогодні.

З.І: Сторонні бібліотеки (та'як boost, наприклад) не чіпаємо, гадаю?

I belong to the Dead Generation.

7 Востаннє редагувалося Bartash (18.03.2013 18:33:45)

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Реалізація на C++:

#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>

using namespace std;

void showFile(const char* /*file*/);

int main(int argc, char* argv[])
{
    if(argc>2) /* Перевірка наявності параметра-імені файлу */
        showFile(argv[1]);
    return 0;
}

/* Макрос прибирання табуляцій по краях рядка: стандартних засобів не знайшов, а сторонні бібліотеки не чіпав */
#define trim(s)    { while(s[0]=='\t')    s=s.substr(1); while(s[s.length()-1]=='\t')    s=s.substr(0,s.length()-1);}

void showFile(const char* file)
{
    ifstream f(file);
    string content( (std::istreambuf_iterator<char>(f)), (std::istreambuf_iterator<char>()) ), /* Контейнер вмісту файлу (одразу ініціалізований) */
            line, /* Рядок */
            token; /* Елемент рядка */

    f.close();
    /* Алгоритм будується на потоковому вичитуванні вмісту файлу із подальшим подрібненням */
    istringstream fileStream(content); /* Потік для роботи зі вмістом */
    vector<string> rowTokens; /* Масив складових рядка (вулиці та номеру) */

    while(getline(fileStream,line)) /* Цикл по рядках */
    {
        trim(line);
        istringstream stream(line); /* Потік для рядка */

        while(getline(stream,token, '\t')) /* Парсинг рядка */
            rowTokens.push_back(token);

        if(rowTokens.size() == 2) /* Умова валідації згідно задачі */
            cout<<rowTokens[0].c_str()<<" ---> "<<rowTokens[1].c_str()<<endl;

        rowTokens.clear();
    }
}

Файл зі вхідними даними передається як параметр під час запуску (для спрощення):

$ myprog file.txt

Потокова обробка може видатися дивною, однак вона дозволяє суттєво зменшити та певним чином спростити обсяг коду. Сторонні бібліотеки на кшалт Boost, Qt та ін. дозволяють це зробити ще простіше (завдяки макросам foreach, зокрема). У даному ж випадку - стандартні можливості С++ та STL.

I belong to the Dead Generation.

8

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Я за Bash smile

з радістю почитаю і перевірю ваш варіант реалізації ;)

2Bartash куль а можна побачити вивід ;)

9 Востаннє редагувалося Bartash (17.03.2013 20:57:31)

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

funivan написав:

2Bartash куль а можна побачити вивід ;)

Звісно.

http://s7.postimage.org/h3g74vjrv/res.jpg

Post's attachments

file.txt 141 b, 212 downloads since 2013-03-17 

I belong to the Dead Generation.

10

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Bartash написав:

Давайте тоді уже приклади робити різними мовами, а не тільки трьома у назві теми. :)

JAVA

public class ParseFile {
    public static void main(String[] args) {
        try (java.util.Scanner scanner = new java.util.Scanner(new java.io.File(args[0]))) {
            while (scanner.hasNextLine()) {
                String[] str = scanner.nextLine().replaceAll("^\t+|\t$+", "").split("\t");
                if (str.length == 2) {
                    System.out.printf("%s ---> %s\n", str[0], str[1]);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

11 Востаннє редагувалося funivan (18.03.2013 15:12:44)

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Тему оновив =) Лишилось рубі і баш ;)

Народ все кльово, тільки можливо давайте вивід будемо робити якийсь хоча б подібний.
Victor чекаю вивід)
Барташ якщо можна форматування поправте.
А і ще одне маленьке прохання, можливо хоч трохи коментарів, думаю народові і мені теж буде цікаво зрозуміти що і як. Приблизно ясно але все ж таки ;) Всім дякую за участь ;)

12

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

funivan написав:

...
Victor чекаю вивід)
...

Прихований текст

javac ParseFile.java


java ParseFile 01.txt
вул. Сергія Єфремова ---> 1/2
вул. 100-Р.Червоного Хреста ---> 1
вул. 100-Р.Червоного Хреста ---> 2
вул. 100-Р.Червоного Хреста ---> 3
вул. 100-Р.Червоного Хреста ---> 2в
вул. 2000-Ліття Різдва Христового ---> 4
вул. 24 Серпня ---> 1

java ParseFile file.txt
Simple street ---> 222
street with forward tabs ---> 111
street with tabs at the end ---> 222

file.txt брав тут

Post's attachments

01.txt 204 b, 212 downloads since 2013-03-18 

13

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Добавив дякую ;)

14

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

bash
> cat ParseFile.sh

#!/bin/bash
mIFS="$IFS"
IFS=$'\n'
while read line
do
    str=$line
    str="${str#"${str%%[![:space:]]*}"}" #//не зовсім, але ...
    str="${str%"${str##*[![:space:]]}"}" #//не зовсім, але ...

    IFS=`/bin/echo -ne "\t"` read -a array <<< "$str"
    if [ ${#array[*]} -eq  2 ]
    then
        printf '%s ---> %s ' "${array[0]}" "${array[1]}"; printf '\n'
    fi
done <$1|iconv -f CP1251 -t UTF-8
IFS="$mIFS"
Прихований текст

> ./ParseFile.sh 01.txt
вул. Сергія Єфремова ---> 1/2
вул. 100-Р.Червоного Хреста ---> 1
вул. 100-Р.Червоного Хреста ---> 2
вул. 100-Р.Червоного Хреста ---> 3
вул. 100-Р.Червоного Хреста ---> 2в
вул. 2000-Ліття Різдва Христового ---> 4

> ./ParseFile.sh file.txt
Simple street ---> 222
street with forward tabs ---> 111
street with tabs at the end ---> 222

посилання на файли  у попередньому дописі

p.s.
під руками є postgresql, можна і на pl/pgsql.

15

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Круто. Пора придумувати нову задачу. ;) Victor додав ваш код в тему ;)

16

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

funivan написав:

Барташ якщо можна форматування поправте.
А і ще одне маленьке прохання, можливо хоч трохи коментарів, думаю народові і мені теж буде цікаво зрозуміти що і як. Приблизно ясно але все ж таки ;) Всім дякую за участь ;)

Коментарі додав. Форматування коду причепурив, якщо ви про це говорили. :)

I belong to the Dead Generation.

17

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

funivan написав:

Народ все кльово, тільки можливо давайте вивід будемо робити якийсь хоча б подібний.

Не проблема: тільки стандарт вкажіть. :)
Головне, щоб наочно і зручно для перегляду було.

I belong to the Dead Generation.

18 Востаннє редагувалося Victor (18.03.2013 18:56:16)

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

funivan написав:

Круто.

там є помилка. Якщо в останній стрічці немає CHR(13) ("\n"), то вона не обробляється.
Підправлений код:
> cat ParseFile.sh

#!/bin/bash

mIFS="$IFS"

while IFS=$'\n' read -r line || [[ -n "$line" ]]
do
    str=$line
    str="${str#"${str%%[![:space:]]*}"}" #//не зовсім, але ...
    str="${str%"${str##*[![:space:]]}"}" #//не зовсім, але ...

    IFS=$'\t' read -a array <<< "$str"
    if [ ${#array[*]} -eq  2 ]
    then
        printf '%s ---> %s ' "${array[0]}" "${array[1]}"; printf '\n'
    fi
done <$1|iconv -f CP1251 -t UTF-8

> ParseFile.sh 01.txt

вул. Сергія Єфремова ---> 1/2
вул. 100-Р.Червоного Хреста ---> 1
вул. 100-Р.Червоного Хреста ---> 2
вул. 100-Р.Червоного Хреста ---> 3
вул. 100-Р.Червоного Хреста ---> 2в
вул. 2000-Ліття Різдва Христового ---> 4
вул. 24 Серпня ---> 1

19 Востаннє редагувалося ADR (19.03.2013 15:58:33)

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

Delphi (не провіряв вивід, але воно компілюється:)

program ParseBuildings;
{$APPTYPE CONSOLE}
uses
  Classes;
var
  StrList: TStringList;
  I: Integer;
begin
  StrList := TStringList.Create; // Створюємо об’єкт типу "список рядків"
  with StrList do // Для доступу до методів об'єкта без префікса "StrList."
    try
      LoadFromFile('buildings.txt'); // Загружаємо файл у StrList
      NameValueSeparator := '    '; // Міняємо роздільник імен/значень (по замовчуванню був знак "=")
      //тобто тепер виходить така маска '<name><tab><value>'
      for I := 0 to Count -1 do
      begin
        Strings[i] := Trim(Strings[i]); // Обрізаємо недруковані символи по боках поточного рядка
        if Pos('    ', ValueFromIndex[i]) = 0 then 
        // якщо value містить таби значить їх було більше одного
          WriteLn(Names[i] + ' | ' + ValueFromIndex[i]) // Виводимо пари
      end;
    finally
      StrList.Free; // і прибираємо за собою
    end;
end.

Є текст "123=123=123".
Якщо StrList.NameValueSeparator = '=' то
StrList.Name[0] = "123"
StrList.ValueFromIndex[0] = "123=123"
і оскільки у Value є розділювач (Pos('=', StrList.ValueFromIndex[0]) > 0) значить таких було більше одного.

Тільки у нас таби замість знаків рівності


with do - не рекомендовано використовувати коли не зрозуміло де чиї методи, але так як у нас всього одни об'єкт то можна)

Подякували: Torbins1

20

Re: Обробка файлу PHP & Python & Ruby & С++ & Java та багато інших

SQL+Postgresql

> psql -a -t -d postgres -p 5432 -h 127.0.0.1 -c "\
select str[1]||' ---> '||str[2]
  from (select string_to_array( regexp_replace(line, '(^[\s\t\n\r]+|[\s\t\n\r]+$)', '', 'g'), e'\t') as str\
          from unnest(string_to_array(convert_from(pg_read_binary_file('./01.txt'), 'win1251'), e'\n')) as foo (line)) foo\
 where array_length(str, 1) = 2"
 вул. Сергія Єфремова ---> 1/2
 вул. 100-Р.Червоного Хреста ---> 1
 вул. 100-Р.Червоного Хреста ---> 2
 вул. 100-Р.Червоного Хреста ---> 3
 вул. 100-Р.Червоного Хреста ---> 2в
 вул. 2000-Ліття Різдва Христового ---> 4
 вул. 24 Серпня ---> 1

PLPGSQL+Postgresql

DO $$
DECLARE
  loidTxt oid;
  lfdTxt integer;
  fileTxt bytea;
  sizeTxt integer;
  line record;
  rec record;
BEGIN
        loidTxt := lo_import('./01.txt');
        lfdTxt := lo_open(loidTxt, X'20000'::int);
        sizeTxt       := lo_lseek(lfdTxt,0,2);
        perform lo_lseek(lfdTxt,0,0);
        fileTxt       := loread(lfdTxt,sizeTxt);
        --raise NOTICE '%', convert_from(filetxt, 'win1251');
        for line in SELECT UNNEST(string_to_array(convert_from(filetxt, 'win1251'), E'\n')) AS l
        LOOP
           for rec in select string_to_array( regexp_replace(line.l, '(^[\s\t\n\r]+|[\s\t\n\r]+$)', '', 'g'), E'\t') AS str
           LOOP
                IF array_length(rec.str,1)=2
                THEN
                        raise NOTICE '% ---> %', rec.str[1], rec.str[2];
                END IF;
           END LOOP;
        END LOOP;

        perform lo_close(lfdTxt);
        perform lo_unlink(loidTxt);

END $$;
NOTICE:  вул. Сергія Єфремова ---> 1/2
NOTICE:  вул. 100-Р.Червоного Хреста ---> 1
NOTICE:  вул. 100-Р.Червоного Хреста ---> 2
NOTICE:  вул. 100-Р.Червоного Хреста ---> 3
NOTICE:  вул. 100-Р.Червоного Хреста ---> 2в
NOTICE:  вул. 2000-Ліття Різдва Христового ---> 4
NOTICE:  вул. 24 Серпня ---> 1
Подякували: Bartash1